Valentin T.
Valentin T.

Reputation: 529

C++ covariant return type error with multiple inheritance

I have the code which is equivalent to this one:

class X {};
class Y {};

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

class A : public C< X> {
public:
    X * foo() {};
};

class B : public A {};

class D : public B, public C< Y> {
public:
    Y * foo() {}; //this is the only one method I need here. Not A::foo!
};

I got this errors:

error:   invalid covariant return type for 'virtual Y* D::foo()'
 Y * foo() {};
     ^

and:

error:   overriding 'virtual X* A::foo()'
 X * foo() {};
     ^

http://ideone.com/PAgTdX

I believe I could write something in class B or D to prevent A::foo from inheriting, but I don't know what. Maybe there is some feature to rename conflict names in C++?

PS> I can't use C++11, only good old C++98.

Upvotes: 5

Views: 777

Answers (3)

masoud
masoud

Reputation: 56479

TL;DR

Overriding foo in class D. foo methods can not covariant due to unrelated X and Y return types. Neither, can not overload due to different return types but same signature.


Explanation

Let's clean up the code to a smaller snippet with same issue:

class X {};
class Y {};

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

class A : public C<X> {
public:
    // Your code:
    // X * foo() {}; <---- This method is irrelevant to the problem

    // virtual X * foo() {};
    // ^^^^^^^^^^^^^^^^^^^^^
    // This method declared via inheritance and template
    // and implicitly exists in this class, (look at keyword `virtual`)
};

class D : public A, public C<Y> {
public:
    /*virtual*/ Y * foo() {}; // `virtual` comes from C<X>
};

Well, class D inherits two foo methods from A and C<Y>. These two imported methods can co-exists because they come from different parents and they can be called by qualified calls, for example D d; d.A::foo();.

 

But in this situation, the problem comes into the picture, when you try to override foo in class D:

/*virtual*/ Y * foo() {};

In class D, there is a method with signature X * foo() inherited from A and you're overriding method Y * foo(). These can not covariant, because Y is not derived from X. On the other hand, this foo can not overload another one, Because return type is not part of function signature.

 

It's good to read the error message of clang:

error: return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('Y *' is not derived from 'X *')

virtual Y * foo() {};

Solution

The best solution is to simplify your design and get rid of these complex inheritance, templated and same name methods!!

Upvotes: 4

Kristian Duske
Kristian Duske

Reputation: 1779

You are saying that you don't need the foo method you declare in C<X> and implement in A, but since your class D also is-an A and a C<X>, clients might depend on this method being available, and returning an X. C++ doesn't support removing inherited methods AFAIK, and for good reason, as this would violate the Liskov substitution principle.

If you did remove or hide C<X>::foo here, then an instance of D could not be used where an instance of A, B, or C<X> is expected. So I'm afraid that there is no good solution for this problem here. If you are only trying to reuse implementation from A or B in D, then maybe you should consider composition instead of inheritance in this case.

Upvotes: 0

qznc
qznc

Reputation: 1173

You could use private inheritance for A.

class B : private A {};

In general, the return type cannot be the only difference for overloading.

Upvotes: -1

Related Questions