【发布时间】: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<base> 和foo<derived> 之间构建继承,例如,通过使用一些代理模板或特殊模式(如 CRTP)在模板实例化后重建相同的继承?
【问题讨论】:
-
不清楚你在问什么。如果您使用
base *,它将适用于您的所有示例。 “使继承保持不变”是什么意思?一样什么? -
foo<base>和foo<derived>是完全不相关的类。两者都继承自base,因此将指针转换为base*是可以的。首选static_cast和dynamic_cast,不要使用 C 风格的强制转换。然后编译器将帮助您防止无效转换。 -
简短的回答是:不,没有。 C++ 中的模板不是这样工作的。当您说“应用模板”时,您会偏离轨道。模板不会被“应用”。他们被实例化。实例化意味着创建了一个新类。例如,类的名称恰好是
foo<base>。但它是一个类,从根本上说,它与一个名为foo或bar的类没有什么不同。现在,以您的示例为例,删除模板并显式创建两个名为A和B的类来代替foo<base>和foo<derived>,您将能够自己回答您的问题。 -
@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