c++ - CRTP 基类型使用的成员变量应该在派生类型中吗?

标签 c++ crtp

我今天一直在学习 CRTP(奇怪的重复模板模式),相信我已经足够了解它了。

但是,在我看到的示例中,状态存储在派生类型中,即使基类型依赖于它们的存在。对我来说,这似乎不合逻辑,成员变量应该在基类型中,因为它的功能依赖于它们。

下面是我所说内容的一个简单示例:

template <typename DerivedType>
class Base{
public:
    int calculate() {
        return static_cast<DerivedType&>(*this).x + static_cast<DerivedType&>(*this).y;
    }
};

class Derived : Base<Derived>{
public:
    int x; // ignore the fact that these aren't initialised for simplicity
    int y;
};

我的问题是:

我认为成员 xy 在基类型中会更好吗?如果不是,为什么?

最佳答案

简答

这取决于你需要做什么,但是如果不同的派生类提供不同类型的x, y , 那么这些不能在基类中。

长答案

继承的最常见用途是基类包含许多(多个)派生类中共有的任何内容。这个公共(public)部分只写一次并被每个派生类重用,导致更短、更清晰的代码、更容易维护等。公共(public)部分是 calculate()在你的情况下。

现在,只要此公共(public)代码需要访问每个派生类的专用信息,就需要通过公共(public)接口(interface)访问此信息。在您的示例中,此信息是成员 x, y每个派生类的类型可能不同。或者,它可以是成员函数 x(), y() .这些函数可以采用不同类型(但数量相同)的参数,并且每个派生类具有不同的返回类型。

无论哪种方式,派生类的工作都是为异构信息提供通用接口(interface)。对于 CRTP/静态多态性,在成员函数的情况下,这个公共(public)接口(interface)仅仅是成员的名称和参数的数量。对于动态多态,相关机制是虚函数,公共(public)接口(interface)包括函数的整个签名。

数据实际存储在哪里并不重要;这取决于很多事情。很可能数据毕竟存储在基类中,但是它们仍然可以通过派生类中的成员函数访问。

一个例子是元组实现,其中 base class实现了不同类型元组之间的所有通用功能,而许多 tuple views从这个基础派生到模型操作,如 flipping元组元素的顺序,concatenating"zipping"元组等。请注意,所有此类 View 都是惰性 View ,类似于 std::reverse_iterator 的方式。允许您以相反的顺序遍历序列,而无需提前实际操作数据。

在这种情况下,成员函数at()基类提供对元组元素的随机访问。这称为 call_at()派生类访问实际存储在基类中的数据。所以,每个派生类只知道在哪里可以找到每个元素;使用此信息,基类实现所有剩余的功能(例如,一个 operator[] 产生一个新的元组,其中每个元素都是将 operator[] 应用于原始元组的相应元素的结果)。

D 的 template mixins提供比 CRTP 更方便、更简洁的替代方案;几乎和宏一样方便。你的static_cast<DerivedType&>(*this).x和我的 der().x将只是 x在这种情况下。另外,您不需要 DerivedTypeBase 内完全没有。

关于c++ - CRTP 基类型使用的成员变量应该在派生类型中吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25048534/

相关文章:

C++ 获取对象

c++ - 嵌套类型的 CRTP

c++ - 写入/创建文件 C++ 时遇到问题

c++ - C++中栈变量的删除

C++ 无法填充数据

c++ - 无法在 OpenCV 中加载和叠加透明图像

c++ - 在 CRTP 的基类中使用 `this` 作为指向派生类的指针

c++ - 继承通用成员函数

c++ - CRTP:从基调用派生类模板化方法

c++ - 继承和CRTP