Using subclass type parameters in virtual functions

馋奶兔 提交于 2020-01-12 04:38:26

问题


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 problems understanding the extension to A* Run();

class A { };

class ExtendsA : public A { };

class B
{
public:
    virtual ~B(){}  
    virtual void Run(A* a) = 0;
    virtual A* Run() = 0;
};

class ExtendsB : public B
{
public:
    virtual ~ExtendsB(){}

    // Not OK! It does not see it as an implementation of 
    // virtual void Run(A* a) = 0;
    virtual void Run(ExtendsA* ea) {}; 
    virtual ExtendsA* Run() { return new ExtendsA(); }; // OK
};

Why C++ allows to change the return type to a sub-class, but not the parameter type?

Is it a good rationale or just a missed point in the language specifications?


回答1:


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.




回答2:


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




回答3:


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




回答4:


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.



来源:https://stackoverflow.com/questions/12369206/using-subclass-type-parameters-in-virtual-functions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!