Vyt*_*ius 6 c++ polymorphism standards templates crtp
class A {
virtual A* foo() = 0;
};
template<class T>
class B : public A {
virtual T* foo() { return nullptr; }
};
class C : public B<C> {
};
Run Code Online (Sandbox Code Playgroud)
这是混合复合图案和奇怪重复模板图案的可能性的简化实现.我收到以下错误:
Return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('C *' is not derived from 'A *')
Run Code Online (Sandbox Code Playgroud)
在clang 3.0,gcc 4.7和visual studio 2008上测试过.
第一解决方案
class C : public A, public B<C> {}
Run Code Online (Sandbox Code Playgroud)
在Visual Studio中编译一个警告B是已经是一个孩子,并没有下与初始误差铛编译.
另一种解决方法:
class D : public A {}
class C : public B<D> {}
Run Code Online (Sandbox Code Playgroud)
解决了不完整性问题,但我无法弄清楚我将拥有多少个A实例.直觉告诉我A是虚拟的,因此应该只有一个.
此解决方法还会创建无法读取的代码.
标准对这种情况有何规定?这段代码应该编译吗?如果没有,为什么?
您的虚拟函数A::foo()返回一个A*,而B<C>::foo()旨在覆盖它的函数则返回一个C*。
理论上,这确实尊重协变原则,因为C确实是 (派生自) 的特化A,但在实例化时,这是未知的,因为它C是不完整的类型。
重新思考设计的一种可能方法是创建A一个类模板,并让B模板参数传播T最多A:
template<typename T>
class A {
virtual T* foo() = 0;
};
template<class T>
class B : public A<T> {
virtual T* foo() { return nullptr; }
};
Run Code Online (Sandbox Code Playgroud)
关于您的解决方法:
标准对这种情况有何规定?这段代码应该编译吗?如果没有,为什么?
C它不应该编译,因为 make也显式派生的事实A(注意,您最终会得到内部类型的两个不同的基本子对象)在实例化 时并不能生成完整的类型。根据 C++11 标准第 9.2/2 段:ACCB<C>
在类说明符
}结束时,类被视为完全定义的对象类型 (3.9)(或完整类型)。 在类成员规范中,类在函数体、默认参数和非静态数据成员的大括号或等于初始化器(包括嵌套类中的此类内容)中被视为完整。否则,它在其自己的类成员规范中被视为不完整。