【问题标题】:How to make the templated classes keep the inheritance?如何使模板类保持继承?
【发布时间】:2018-05-05 19:23:48
【问题描述】:

以下是我的想法的简化代码。

#include <iostream> 

struct base {
    virtual int test(){return 0;}
};

struct derived : public base {
    virtual int test(){return 1;}
};

template <typename T>
struct foo : public T {
    virtual int  bar() { return 2;}
};


typedef foo<base> foo_base;
typedef foo<derived> foo_derived;

int main(int argc, char ** argv) {

base * p = new derived(); //It is OK.
std::cout<<p->test()<<std::endl;

foo_base * foo_p = new foo_derived(); //It is not OK 
std::cout<<foo_p->bar()<<std::endl;

foo_base * foo_p2 =(foo_base *)(new foo_derived()); //It is working 
std::cout<<foo_p2->bar()<<std::endl;

delete foo_p2;
delete foo_p;
delete p;

return 0;
}

由于模板更改了类继承,我知道这是不行的。有没有一种优雅的方法可以在应用模板后使继承保持不变?

更具体地说,是否可以在foo&lt;base&gt;foo&lt;derived&gt; 之间构建继承,例如,通过使用一些代理模板或特殊模式(如 CRTP)在模板实例化后重建相同的继承?

【问题讨论】:

  • 不清楚你在问什么。如果您使用base *,它将适用于您的所有示例。 “使继承保持不变”是什么意思?一样什么?
  • foo&lt;base&gt;foo&lt;derived&gt; 是完全不相关的类。两者都继承自base,因此将指针转换为base* 是可以的。首选 static_castdynamic_cast,不要使用 C 风格的强制转换。然后编译器将帮助您防止无效转换。
  • 简短的回答是:不,没有。 C++ 中的模板不是这样工作的。当您说“应用模板”时,您会偏离轨道。模板不会被“应用”。他们被实例化。实例化意味着创建了一个新类。例如,类的名称恰好是foo&lt;base&gt;。但它是一个类,从根本上说,它与一个名为 foobar 的类没有什么不同。现在,以您的示例为例,删除模板并显式创建两个名为 AB 的类来代替 foo&lt;base&gt;foo&lt;derived&gt;,您将能够自己回答您的问题。
  • @super 对我不清楚的表达感到抱歉。我知道如果对所有指针都使用 base * ,就不会有问题。但是,代码只是真实代码的简化版本。我想将模板中的bar等一些函数添加到原始框架中,并希望通过使用命名空间别名(例如using base = myns::foo_base)将所有(base *)替换为(foo_base *),只是为了保持原代码不变。在这种情况下,我找不到一种简单的方法来即时进行更改。
  • @SamVarshavchik,感谢您的回复。事实上,我不太同意你的观点,即实例化后 A 和 B 不相关。在 C_style cast 之后,或者使用 reinterpret_cast 之后,你会发现 foo_derived 确实可以使用,如果你尝试 foo_p2->test(),它会返回 1,正如我们所期望的那样。

标签: c++ templates inheritance


【解决方案1】:

正如Sam Varshavchik 在 cmets 中所说,您无法完全自动化此过程,因为 C++ 没有反射,因此无法列出基类。但是,您已经走上了typedefing 模板实例化的路线,这是您自己列出基类的理想场所(在 cmets 中突出显示的问题):

struct base {
    // Don't forget the virtual destructor for polymorphic destruction
    virtual ~base() = default;

    virtual int test() const { return 0; }
};

struct derived : base {
    int test() const override { return 1; }
};

// U... is the list of thebase classes for T
template <typename T, typename... U>
struct foo : T, foo<U>... {
    //        ^^^^^^^^^^^ Inheritance is mirrored here

    virtual int bar() const { return 2; }
};

// base has no base class
typedef foo<base> foo_base;

// derived has one base class, base.
typedef foo<derived, base> foo_derived;

Live example on Coliru

【讨论】:

    猜你喜欢
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-18
    • 2011-03-22
    相关资源
    最近更新 更多