class A {
virtual A* foo() = 0;
};
template<class T>
class B : public A {
virtual T* foo() { return nullptr; }
};
class C : public B<C> {
};
这是Possibility to mix composite pattern and curiously recurring template pattern的简化实现。我收到以下错误:
Return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('C *' is not derived from 'A *')
在clang 3.0,gcc 4.7和visual studio 2008上测试过。
第一个解决方案:
class C : public A, public B<C> {}
在视觉工作室下编辑,警告B已经是A的孩子,并且不在clang下编译并出现初始错误。
另一种解决方法:
class D : public A {}
class C : public B<D> {}
解决了不完整性问题,但我无法弄清楚我将拥有多少个A实例。直觉告诉我A是虚拟的,因此应该只有一个。
此解决方法也会创建无法读取的代码。
该标准对此情况有何规定?这段代码应该编译吗?如果没有,为什么?
答案 0 :(得分:4)
您的虚拟函数A::foo()
会返回A*
,而函数B<C>::foo()
会覆盖它,会返回C*
。
这在理论上确实尊重协方差原理,因为C
确实是(派生自)A
的特化,但在实例化时,这是未知的,因为{{1是一种不完整的类型。
重新考虑您的设计的一种可能方法是将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; }
};
的事实也明确地来自C
(注意,你最终会得到两个不同的基础子A
中A
类型的对象在实例化C
时不会使C
成为完整类型。根据C ++ 11标准的第9.2 / 2段:
在类说明符的结束
B<C>
,类被视为完全定义的对象类型(3.9)(或完整类型)。 在类 member-specification 中,该类在函数体内被视为完整, 默认参数,以及非静态数据成员的 brace-or-equal-initializers (包括 嵌套类)。否则,它在其自己的类 member-specification 中被视为不完整。