6
class A {
    virtual A* foo() = 0;
};

template<class T>
class B : public A {
    virtual T* foo() { return nullptr; }
};

class C : public B<C> {

};

这是混合复合模式和奇怪重复的模板模式的可能性的简化实现。我收到以下错误:

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> {}

在 Visual Studio 下编译,并警告 B 已经是 A 的子级,并且不会clang 下编译并出现初始错误。

另一种解决方法:

class D : public A {}
class C : public B<D> {}

解决了不完整性问题,但我无法弄清楚我将拥有多少个 A 实例。直觉告诉我 A 是虚拟的,因此应该只有一个。

此解决方法还会创建不可读的代码。

标准对这种情况有何规定?这段代码应该编译吗?如果不是,为什么?

4

1 回答 1

4

您的虚函数A::foo()返回一个A*,而B<C>::foo()用于覆盖它的函数返回一个C*.

这在理论上确实尊重协变原则,因为C确实是 (derives from)A的一种特化,但在实例化时,这是未知的,因为C它是一个不完整的类型。

重新考虑您的设计的一种可能方法是制作A一个类模板,并让B模板参数传播TA

template<typename T>
class A {
    virtual T* foo() = 0;
};

template<class T>
class B : public A<T> {
    virtual T* foo() { return nullptr; }
};

关于您的解决方法:

标准对这种情况有何规定?这段代码应该编译吗?如果不是,为什么?

它不应该编译,因为仅仅make的事实C也显式地派生A(注意,你最终会得到两个A不同的inside类型的基本子对象)在实例化. 根据 C++11 标准的第 9.2/2 段:CCB<C>

}class-specifier结束时,类被视为完全定义的对象类型 (3.9)(或完整类型)。 在类成员规范中,类在函数体、默认参数和非静态数据成员(包括嵌套类中的此类内容)的大括号或等式初始化器中被认为是完整的。否则,它在其自己的类成员规范中被视为不完整。

于 2013-03-22T12:40:24.630 回答