So after searching a lot for an answer to my question, I finally gave up on my Google skills.
I have an base class Base, and a derived class Derived. I want to override a type in the Base class with one in the Derived class. Here's an example:
class Apple {
public:
Apple() { }
// ...
};
class Orange {
public:
Orange() { }
// ...
};
class Base {
public:
typedef Apple fruit;
// ...
virtual fruit func() { return Apple(); }
};
class Derived : public Base {
public:
typedef Orange fruit;
// ...
fruit func() override { 开发者_如何学运维return Orange(); } // <-- Error C2555!
};
This code doesn't work, and it gives a
C2555 error ('Derived::func': overriding virtual function return type differs and is not covariant from 'Base::func').
Above was one of solutions I tried. I also tried creating a virtual nested class in the Base, and redefined in Derived, and that didn't compile also (it was also very messy).
I also can't derive Apples and Oranges from the same base class to return pointer/reference to their parent class in Base and Derived. I need to physically return an instance of the object.
- Is there any way I can declare abstract typedefs?
- If not, is there any other solution that could achieve what I'm trying to do?
First of all, look at this syntax :
fruit func() override { return Orange(); }
What is override
? In C++03, there is no such keyword. It's only in C++11. So make sure that you're using a compiler which knows of this keyword.
Second, in the derived class, fruit
is indeed Orange
. Redefining the typedef is not a problem. The problem is, Orange
and Apple
are not covariant type. Deriving one from another will make them covariant. In your case, you've to derive Orange
from Apple
in order to make it work.
Note you've to change the return type from fruit
to either fruit*
or fruit&
.
class Orange : public Apple {}; //correct - your code will work
class Apple : public Orange {}; //incorrect - your code will not work
The idea is, in the base class, the return type should be pointer/reference of base type (which is Apple
), and in the derived class, the return type can be pointer/reference of type Apple
or any class which derives from it.
By the way, does this make sense? Deriving Orange
from Apple
?
How about the following class-design?
class Fruit {};
class Apple : public Fruit {};
class Orange : public Fruit {};
class Base
{
virtual Fruit* f();
};
class Derived : public Base
{
virtual Fruit* f();
};
No need to use typedef
.
This does not make much sense to begin with. A Derived
should be able to be used anywhere a Base
is expected, so you should be able to do
Base *foo = new Base();
Apple x = foo->func(); // this is fine
Base *bar = new Derived();
Apple y = foo->func(); // oops...
I think you need to look into a different design. It's not clear just what your goal is here, but I'm guessing you might either want Base
to be a class template with Fruit
as a template parameter, or maybe you need to get rid of the inheritance altogether.
You can't really do that, if you have a value object, you must know which type it is. (This is one of the major differences between a statically typed language like C++ and dynamically typed languages like Ruby and Python.)
There are many ways around this. First, let's assume that Apple
and Oragne
has a common base class called Fruit
. One solution is to dynamically allocate the object using new
and return a Fruit
-pointer.
Another solution, instead of returning a value, your function could take a pointer or reference to a Fruit which it then could fill in.
Yet another solution is to have some kind of container object that internally would hold either an Apple or Orange. That way you could return it.
The reported error tells you all you need. What it means is that the type returned in the Derived
method needs to be derived from the type returned in the base method.
This is so that if the base method is called virtually, the returned object can be viewed as that returned by the base method.
Actually, you'd need to return a pointer or reference to do this.
What you will need to do is define a new Fruit
base class, and have Apple
and Orange
derive from it.
Then have func()
return a Fruit*
.
That will leave you with the problem of making sure the Fruit*
is delete
'd at some point.
With a bit more context, I suspect that (probably thin) templating is the solution you are after, rather than inheritance.
精彩评论