如果基类Base
有两个派生类DerA
和DerB
,派生类是否可以在Base
成员函数中使用成员变量,但每个班级的类型不同?
class Base {
* a // Declare a as *something*, so it can be used by "doWork"
template <typedef T>
void doWork(T b) { // Add another value to "a" which is of its same type
a += b; // For example; an operation that works on "a", no matter what numeric type it is
}
}
class DerA : public Base {
// Make "a" an int
}
class DerB : public Base {
// Make "a" a float
}
实际上,a
将是一个基本结构,而DerA
和DerB
将具有基本结构的派生版本(衍生类将各自具有特定结构的派生形式)为了他们的目的,但每个人都必须在a
上做一个简单的操作,所以当我只能使用模板函数时,复制/粘贴每个衍生物的简单函数似乎没有意义。我只需键入a
作为基本结构类型,但后来我无法访问每个派生结构所具有的各种专用成员函数和变量(如果我正确理解了继承)。
如果这个问题重复,我道歉,但我不知道这个质量会被称为什么,所以谷歌搜索没有结果。
答案 0 :(得分:3)
您可能想要的是CRTP。
template<class D>
struct Base {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
template<class T>
void doWork(T b) {
self()->a += b;
}
};
struct DerA : public Base<DerA> {
int a;
};
struct DerB : public Base<DerB> {
double a;
};
这里我们将派生类型传递给我们的基类。在基类中,您可以使用self()->
访问派生类型中的字段。这允许基本上完全访问派生类型,同时让我们在基类中共享代码。
请注意,您无法以DerA
方式传递DerB
和Base
。如果您需要,则需要virtual
方法doWork
,并且virtual
template
方法不存在。
CRTP代表了奇怪的重复模板模式,我想这个模板是因为它很奇怪,它涉及重复一种类型,并且它会在奇怪的角落里显示为有用。
类型擦除可能也不起作用,因为你想从代码库中的两个不同点发送类型擦除(双重调度问题:你需要一个集中的类型列表,支持类型笛卡尔积)
要对此进行扩展,为了支持a+=b
和a
都是任意类型的b
,您必须两次扩展所有类型,包括从不类型在编译单元的相同位置相互可见。这是不可能的。
如果您需要一个公共基础,并且只有一些类型传递给doWork
,请按以下步骤操作:
struct Base {
virtual void doWork( double ) = 0;
virtual void doWork( int ) = 0;
virtual void doWork( long long ) = 0;
};
template<class D>
struct Base_helper:Base {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
template<class T>
void doWork_impl(T b) {
self()->a += b;
}
void doWork( double x ) override { doWork_impl(x); };
void doWork( int x ) override { doWork_impl(x); };
void doWork( long long x ) override { doWork_impl(x); };
};
struct DerA : public Base_helper<DerA> {
int a;
};
struct DerB : public Base_helper<DerB> {
double a;
};
请注意,doWork
的每个版本必须有效才能调用每个Der
,因为Base_helper
会实例化所有版本。
如果传递给doWork
的类型无限制,但Der
的类型有限,则可以向后执行上述类似的操作。然而,它变得尴尬。在这种情况下,最好的办法是使用boost::variant
类型的解决方案。
答案 1 :(得分:2)
我想你想要实现这样的目标:
template<typedef T>
class Base {
T a;
void doWork(T b) { // Add another value to "a" which is of its same type
a += b; // For example; an operation that works on "a", no matter what numeric type it is
}
}
class DerA : public Base<int> {
}
class DerB : public Base<float> {
}
或者您可以完全转储类DerA和DerB并改为使用typedef:
typedef Base<int> DerA;
typedef Base<float> DerB;
答案 2 :(得分:2)
这可以通过类似CRTP的模式轻松解决:
template<class D> // Base class is templated
class Base {
public:
D a;
void doWork(D b) {
a += b;
}
};
class DerA : public Base<int> {};
class DerB : public Base<float> {};
编辑:如果您只需要一个公共基础(Base<int>
是与Base<float>
完全不同的类型),您可以使用接口类并从中继承Base。