c – 更改继承中的成员类型
给定具有两个派生类(DerA和DerB)的基类Base,派生类是否可以在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执行简单操作,因此当我可以使用模板函数时,复制/粘贴每个衍生物的简单函数似乎毫无意义).我只是键入一个作为基本结构类型,但后来我失去了访问每个派生结构所具有的各种专用成员函数和变量(如果我正确理解继承). 如果这个问题重复,我道歉,但我不知道这个质量会被称为什么,所以谷歌搜索证明没有结果. 解决方法
你可能想要的是
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传递.如果需要,您需要虚拟方法doWork,并且不存在虚拟模板方法. 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必须有效才能调用每个Ders,因为Base_helper会实例化所有版本. 如果传递给doWork的类型是无限制的,但是Der的类型是有界的,那么你只能向后执行类似上面的操作.然而,它变得尴尬.在这种情况下,最好的选择是使用boost :: variant类型的解决方案. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |