C ++:如何在没有强制转换的情况下避免继承类中的“无效协变返回类型”?

时间:2010-03-09 16:16:51

标签: c++ inheritance covariance

我有一个相当复杂的类层次结构,其中类是相互依赖的:有两个抽象类A和C,它们分别包含一个返回C和A实例的方法。在他们继承的类中,我想使用一个co-variant类型,在这种情况下是一个问题,因为我不知道一种方法来转发声明继承关系。

我获得了一个“test.cpp:22:错误:'虚拟D * B :: outC()'的无效协变返回类型” - 错误,因为编译器不知道D是C的子类。

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

如果我将B :: outC()的返回类型更改为C *,则编译示例。有没有办法将B *和D *保留为继承类中的返回类型(对我来说,有一种方法可以直观)?

3 个答案:

答案 0 :(得分:8)

我知道在C ++中无法直接耦合协变成员。您将要么添加一个图层,要么自己实现协变回报。

第一个选项

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class BI : public A {
public:
};

class D : public C {
public:
        BI* outA();
};

class B: public BI {
public:
        D* outC();
};

D* B::outC() {
        return new D();
}

BI* D::outA() {
        return new B();
}

和第二次

class C;

class A {
public:
        C* outC() { return do_outC(); }
        virtual C* do_outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
        virtual C* do_outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return static_cast<D*>(do_outC());
}

C* B::do_outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

请注意,第二个选项是编译器隐式执行的操作(使用static_cast有效的静态检查)。

答案 1 :(得分:4)

据我所知,如果没有明确的演员,就没有办法做到这一点。问题是类B的定义不能知道DC的子类,直到它看到类D的完整定义,但定义为类D无法知道BA的子类,直到它看到类B的完整定义,因此您具有循环依赖关系。这不能通过前向声明来解决,因为前转声明很遗憾无法指定继承关系。

尝试使用模板which I found can be solved实现协变clone()方法存在类似的问题,但类似的解决方案仍然失败,因为循环引用仍然无法解决。

答案 2 :(得分:0)

由于客户方的期望,您无法做到这一点。使用C实例时,您无法分辨它是哪种C(D或其他)。因此,如果将B指针(由于对派生类的调用产生但在编译时不知道它)存入A指针,我不确定所有内存都是正确的。

当您在多态类型上调用方法时,运行时环境必须检查对象的动态类型,并移动指针以适应您的类层次结构。我不确定你应该依靠协方差。看看this