让c++类使用通用的用户定义输入
Make a c++ class work with generic user defined inputs
我觉得这个问题以前一定有人问过,但我在谷歌上找不到答案。如果有,请指引我到一个链接,我会删除这个帖子。
考虑一下这个最小的例子,它代表了我遇到的一个更大的问题。假设我创建了一个简单的"点"answers"打印机"类,如下所示:
class Point {
public:
double x, y;
Point() {x = y = 0;}
Point(double x, double y) {
this->x = x; this->y = y;
}
};
template<typename T>
class Printer {
public:
T* mData;
int mSize;
// Constructor
Printer(std::vector<T> &input) {
mData = &input[0];
mSize = input.size();
}
// Simple Print function
void Print() {
printf(" - Showing %d itemsn", mSize);
for (int i = 0; i < mSize; i++) {
const T &item = mData[i];
printf(" - Item %d: (%lf, %lf)n", i, item.x, item.y);
}
}
};
我可以像这样使用打印机类:
std::vector<Point> points; // fill the vector, and then...
Printer<Point> pointsPrinter(points); pointsPrinter.Print();
现在假设有其他人出现并希望使用Printer类,其中有自己的"Point"类声明如下:
class Pnt {
public:
double mX, mY;
// other stuff
};
如果他们试图这样做:
vector<Pnt> pnts; // Fill the pnts, and then...
Printer<Pnt> pntsPrinter(pnts);
pntsPrinter.Print(); // COMPILE ERROR HERE!
显然,这将失败,因为Pnt没有x或y成员。有没有一种方法可以重写Printer类来处理所有通用用户类型?我不想做的是将Pnt向量复制到Points向量中。
编辑:
我能想到的唯一方法就是传递函数指针。类似这样的东西:
template<typename T>
class Printer {
public:
T* mData;
int mSize;
double* (*mXFunc) (T*);
double* (*mYFunc) (T*);
Printer(std::vector<T> &input,
double* (*xFunc) (T*),
double* (*yFunc) (T*))
{
mData = &input[0];
mSize = input.size();
mXFunc = xFunc;
mYFunc = yFunc;
}
void Print() {
printf(" - Showing %d itemsn", mSize);
for (int i = 0; i < mSize; i++) {
T &item = mData[i];
printf(" - Item %d: (%lf, %lf)n", i, *mXFunc(&item), *mYFunc(&item));
}
}
};
// Could then use it like so
inline double* getXPointVal(Point *point) {return &point->x;}
inline double* getYPointVal(Point *point) {return &point->y;}
inline double* getXPntVal(Pnt *point) {return &point->mX;}
inline double* getYPntVal(Pnt *point) {return &point->mY;}
Printer<Pnt> pntPrinter(pnts, getXPntVal, getYPntVal);
Printer<Point> pointsPrinter(points, getXPointVal, getYPointVal);
pntPrinter.Print();
pointsPrinter.Print();
这样做的问题是它看起来很难看,还可能引入函数调用开销。但我想函数调用开销会被编译掉吗?我希望有一个更优雅的解决方案。。。
如果选择cout
而不是printf
来编写输出,则可以允许所有可打印类型为<<
运算符定义重载,并在Printer::print()
中通用该重载。过载可能看起来像这样:
std::ostream& operator<<(std::ostream &out, Point& p){
out << "Point(" << p.x << ", " << p.y << ")";
return out;
}
附带说明一下,我建议不要存储指向vector
的内部存储和大小成员的指针。如果向量需要重新分配,则指针将处于悬空状态且无效。相反,您应该将向量临时作为引用传递,或者保留常量引用。
您可以为要使用的每个Point
类定义自由(非成员)函数。这样做的优点是可以稍后定义自由函数,而无需对现有类进行更改。
示例:
namespace A {
class Point {
public:
Point (int x, int y) : x_(x), y_(y) {}
int getX () const { return x_; }
int getY () const { return y_; }
private:
int x_, y_;
};
// in addition, we provide free functions
int getX (Point const & p) { return p.getX(); }
int getY (Point const & p) { return p.getY(); }
}
namespace B {
class Pnt {
public:
Pnt (int x, int y) : x_(x), y_(y) {}
int get_x () const { return x_; }
int get_y () const { return y_; }
private:
int x_, y_;
};
// Pnt does not have free functions, and suppose we
// do not want to add anything in namespace B
}
namespace PointHelpers {
// free functions for Pnt
int getX (Pnt const & p) { return p.get_x (); }
int getY (Pnt const & p) { return p.get_y (); }
}
// now we can write
template <class PointTy>
void printPoint (PointTy const & p) {
using PointHelpers::getX;
using PointHelpers::getY;
std::cout << getX (p) << "/" << getY (p) << std::endl;
}
A::Point p1 (2,3);
B::Pnt p2 (4,5);
printPoint (p1);
printPoint (p2);
如果自由函数与相应的类位于同一个命名空间中,则将通过依赖于参数的名称查找找到它们。如果您不想在该名称空间中添加任何内容,请创建一个helper名称空间并在其中添加免费函数。然后通过using
声明将它们引入作用域。
例如,这种方法类似于STL对begin
和end
所做的操作。
不要指望模板知道给定类/结构的哪些成员对应于您的x
和y
。。。
如果你想创建通用解决方案,你可以告诉你的打印机函数如何使用lambda表达式(c++11解决方案)将给定的对象解释为你的Point
类:
#include <iostream>
class Point {
public:
double x, y;
Point() {x = y = 0;}
Point(double x, double y) {
this->x = x; this->y = y;
}
};
class Pnt {
public:
double mX, mY;
// other stuff
};
template <class P, class L>
void Print(const P &p, L l) {
Print(l(p));
}
void Print(const Point &p) {
std::cout << p.x << ", " << p.y << std::endl;
}
int main() {
Print(Point(1, 2));
Print(Pnt{4, 5}, [](const Pnt &p) -> Point {return Point(p.mX, p.mY);});
}
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 使用用户定义函数的字符串反转
- 用户定义函数中的指针和输入
- Visual C++(VS2017)中用户定义的转换不明确
- 使用用户定义的参数调用future/async并调用类方法
- 带有用户定义类的c++折叠表达式
- g++用户定义的动态链接库上的全局new和delete运算符
- 直接在 unordered_map 的方法中使用哈希,而不是生成哈希的用户定义对象
- 修改"std::set"中用户定义类型的值
- 参数包构造函数在类模板中隐藏用户定义的转换
- MAKE:找不到包含的用户定义的头文件?
- C++:用户定义的显式类型转换函数错误
- 从用户定义的类生成格式字符串?
- 为用户定义的类正确调用复制构造函数/赋值运算符
- C++ 向量与用户定义的类比较?(==, <, >)
- STL 用户定义的二进制操作
- 将用户定义的类型与 std::vector 和 std::sort 一起使用
- 为什么用户定义的函数不按照给定的顺序对相同长度的元素进行排序?
- 使用宏编译时使用用户定义的数学函数,或者仅使用 c++ 中标准数学库中的函数
- C++:用户定义的类,以成员字段作为地址