c++ - 在继承中更改成员类型

标签 c++ templates inheritance

给定一个基类 Base,它有两个派生类 DerADerB,派生类是否可以有一个成员变量用于在 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 将是一个基本结构,而 DerADerB 将具有基本结构的派生版本(派生类将每个都有一个特定于其用途的结构派生形式,但每个都必须对 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()-> 访问派生类型中的字段。这允许基本上完全访问派生类型,同时让我们在基类中共享代码。

请注意,您不能通过这种方式将 DerADerB 作为 Base 传递。如果你想要那样,你需要一个virtual方法doWork,而virtualtemplate方法不存在。

CRTP代表奇怪的重复模板模式,我想这个名字是因为它很奇怪,它涉及重复一个类型,并且它不断出现在奇怪的角落是有用的。


类型删除可能也不起作用,因为您希望从代码库中的两个不同位置分派(dispatch)类型删除(双重分派(dispatch)问题:您需要支持类型的集中列表来执行笛卡尔积类型) .

要对此进行扩展,为了支持 a+=b 其中 ab 都是任意类型,您必须扩展遍历所有类型两次,包括在编译单元中的同一位置永远不会相互可见的类型。这是不可能的。


如果您需要一个公共(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/

相关文章:

java - JVM如何执行继承树结构?

c++ - QVariantMap DBusMenuExporterDBus GLib-GObject-CRITICAL GLib-GObject-警告

c++ - Visual Studio强制在项目的所有编译单元中包含预编译头文件?

c++ - 在不同操作系统上使用 UTF8 时的不同行为算法

javascript - 在 Node.js 插件中使用 std::thread

c++ - 在模板类中实例化嵌套模板函数

具有带模板的构造函数的 C++ 模板类

c++ - 转换 Eigen 矩阵类型时,错误 : expected primary-expression before ‘float’

JButton的Java子类覆盖setEnabled方法问题

c# - View 模型继承和重复模型引用