给定一个基类 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 时,为每个派生复制/粘贴该简单函数似乎毫无意义模板函数)。我只会键入 a
作为基本结构类型,但随后我无法访问每个派生结构具有的各种专用成员函数和变量(如果我正确理解继承的话)。
如果这个问题是重复的,我很抱歉,但我不知道这种品质会被称为什么,所以谷歌搜索没有结果。
最佳答案
您可能需要的是 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代表奇怪的重复模板模式,我想这个名字是因为它很奇怪,它涉及重复一个类型,并且它不断出现在奇怪的角落是有用的。
类型删除可能也不起作用,因为您希望从代码库中的两个不同位置分派(dispatch)类型删除(双重分派(dispatch)问题:您需要支持类型的集中列表来执行笛卡尔积类型) .
要对此进行扩展,为了支持 a+=b
其中 a
和 b
都是任意类型,您必须扩展遍历所有类型两次,包括在编译单元中的同一位置永远不会相互可见的类型。这是不可能的。
如果您需要一个公共(public)基础,并且只有一些类型可以传递给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
类型的解决方案。
关于c++ - 在继承中更改成员类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26001987/