更改继承中的成员类型
Changing member types in inheritance
给定一个基类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
作为基本结构类型,但随后我无法访问每个派生结构具有的各种专用成员函数和变量(如果我正确理解继承(。
如果这个问题是重复的,我很抱歉,但我不知道这种质量会叫什么,所以谷歌搜索被证明是徒劳的。
你可能想要的是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
类型的解决方案。
我想你想实现这样的事情:
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 并改用 typedefs:
typedef Base<int> DerA;
typedef Base<float> DerB;
这可以通过类似 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。
- 如何在c++中定义以struct为数据成员的类中的构造函数
- 使用成员在类中创建 lambda 表达式
- 使用静态成员声明类时遇到问题
- 没有公共构造函数作为另一个类模板成员的类模板
- 我们可以通过 IPC 传递具有动态管理成员的类对象吗?
- 具有 STL 向量类型成员的类的复制内存
- 内存中类位置的成员是否取决于类成员在类定义中的位置?
- C++成员变量类Q_PROPERTY QML 中不可用
- 提升 - 类没有名为"序列化"的成员(抽象类)?
- C++ - 移动具有固定大小的 c 样式数组成员的类的构造函数
- 具有未知结构作为成员的类
- 清除具有已删除赋值运算符的成员的类实例
- 错误:请求成员 .. 是非类类型"char"
- 没有成员的类的<运算符
- 从相同类型的静态成员进行类内初始化
- 如何设计一个始终是另一个类的成员的类
- 使用 Boost::Serialization 序列化具有 std::mt19937_64 成员的类
- C++ 将队列作为成员的类的构造函数和析构函数
- 移动具有常量成员的类的构造和分配
- 如果包含引用成员的类中缺少原始变量,为什么它仍然可以访问?