I have this piece of code (contrived from my real-life trouble)
It cannot compile, complaining ExtendsB does not implement B::Run(A* a)
. However, it has no
Specialising the return type makes the subclass more strict - it will act as an A
. However, restricting the Run
method to accept only a subclass of the original argument makes B
not act as an A
.
Inheritance models an is-a relationship. Your code violates the Liskov Substitution principle.
Why C++ allows to change the return type to a sub-class, but not the parameter type?
C++ standard allows you to use a Covariant return type while overidding virtual functions but does not allow you to modify the function parameters.And yes there is a good rationale behind it.
Rationale:
Overriding essentially means that either the Base class method or the Derived class method will be called at run-time depending on the actual object pointed by the pointer.
It implies that:
i.e: "Every instance where the Base class method can be called can be replaced by call to Derived class method without any change to calling code."
If the above rule was not in place it would leave a window to break the existing code by addition of new functionality(new derived classes).
If you have a function prototype in derived class which differs from base class virtual function w.r.t parameters then the function does not override the base class function, since the above rule gets broken.
However, Covariant return types do not break this rule, because upcasting happens implicitly and a Base class pointer can always point to a derived class object without any casting, hence the Standard enforces this condition of covariant return types on return types.
The error is pretty clear: You need void Run(A*)
in your class ExtendedB
, but you don't have that. All you have is void Run(ExtendedA*)
, but that's not the same: The base class promises to accept any A
-pointer, but your ExtendedB::Run
is pickier and only accepts a narrow subset.
(You're confusing covariance and contravariance, but that is not relevant for C++, since C++ does not allow contravariant overrides.)
It's simply two different types, which makes it two distinct functions with two distinct signatures.
In general, if you're using a compiler that understands C++11, you should use the override keyword on functions that are intended to override another function. In your case, the error became apparent because of the abstract base class, but in other cases such an error can cause a lot of debugging...