简体   繁体   English

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

[英]C++: How can I avoid “invalid covariant return type” in inherited classes without casting?

I have a quite complex class hierarchy in which the classes are cross-like depending on each other: There are two abstract classes A and C containing a method that returns an instance of C and A, respectively. 我有一个相当复杂的类层次结构,其中类是相互依赖的:有两个抽象类A和C,它们分别包含一个返回C和A实例的方法。 In their inherited classes I want to use a co-variant type, which is in this case a problem since I don't know a way to forward-declare the inheritance relation ship. 在他们继承的类中,我想使用一个co-variant类型,在这种情况下是一个问题,因为我不知道一种方法来转发声明继承关系。

I obtain a "test.cpp:22: error: invalid covariant return type for 'virtual D* B::outC()'"-error since the compiler does not know that D is a subclass of C. 我得到一个“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();
}

If I change the return type of B::outC() to C* the example compiles. 如果我将B :: outC()的返回类型更改为C *,则示例将进行编译。 Is there any way to keep B* and D* as return types in the inherited classes (it would be intuitive to me that there is a way)? 有没有办法将B *和D *保留为继承类中的返回类型(对我来说,有一种方法可以直观)?

I know of no way of having directly coupled covariant members in C++. 我知道在C ++中无法直接耦合协变成员。 You'll have either to add a layer, or implement covariant return yourself. 您将要么添加图层,要么自己实现协变回报。

For the first option 第一种选择

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();
}

and for the second 而对于第二个

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();
}

Note that this second option is what is done implicitly by the compiler (with some static checks that the static_cast is valid). 请注意,第二个选项是编译器隐式执行的操作(使用static_cast有效的静态检查)。

As far as I know, there's no way to do this without explicit casting. 据我所知,如果没有明确的演员,就没有办法做到这一点。 The problem is that the definition of class B can't know that D is a subclass of C until it sees a full definition of class D , but the definition of class D can't know that B is a subclass of A until it sees a full definition of class B , and so you have a circular dependency. 问题是,类的定义B不能知道D是的子类C ,直到它看到类的完整定义, D ,但类的定义D可能不知道B是的子类A ,直到它看到B类的完整定义,因此您具有循环依赖性。 This can't be resolved with forward-declarations because a forward declaration unfortunately cannot specify an inheritance relationship. 这不能通过前向声明来解决,因为前转声明遗憾的是无法指定继承关系。

There's a similar problem with trying to implement a covariant clone() method using templates, which I found can be solved , but the analogous solution still fails here because the circular reference remains impossible to resolve. 尝试使用模板实现协变clone()方法存在类似的问题, 我发现可以解决这个问题 ,但类似的解决方案仍然失败,因为循环引用仍然无法解决。

You can't do this due to client side expectation. 由于客户方的期望,您无法做到这一点。 When using a C instance, you can't tell which kind of C it is (a D or something else). 使用C实例时,您无法分辨它是哪种C(D或其他)。 Thus, if you store the B pointer (resulting from a call to the derived class but you don't know it at compile time) into a A pointer, I'm not sure that all the memory stuff will be right. 因此,如果将B指针(由于对派生类的调用产生但在编译时不知道它)存入A指针,我不确定所有内存都是正确的。

When you call a method on a polymorphic type, the runtime environment has to check the dynamic type of the object and it moves pointers to suit to your class hierarchy. 当您在多态类型上调用方法时,运行时环境必须检查对象的动态类型,并移动指针以适应您的类层次结构。 I'm not sure that you should rely on covariance. 我不确定你应该依靠协方差。 Have a look at this 看看这个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM