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

前端 未结 3 1053
情话喂你
情话喂你 2020-12-30 06:55

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 a

相关标签:
3条回答
  • 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). 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.

    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

    0 讨论(0)
  • 2020-12-30 07:18

    I know of no way of having directly coupled covariant members in 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).

    0 讨论(0)
  • 2020-12-30 07:24

    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. 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.

    0 讨论(0)
提交回复
热议问题