Sam*_*Sam 15 c++ polymorphism inheritance
我有这段代码(由我的现实生活中的麻烦设计)
它无法编译,抱怨ExtendsB没有实现B::Run(A* a).但是,理解扩展名没有问题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
};
Run Code Online (Sandbox Code Playgroud)
为什么C++允许将返回类型更改为子类,而不是参数类型?
这是一个很好的理由还是仅仅是语言规范中的遗漏点?
Alo*_*ave 16
为什么C++允许将返回类型更改为子类,而不是参数类型?
C++标准允许您在覆盖虚函数时使用Covariant返回类型,但不允许您修改函数参数.是的,它背后有一个很好的基本原理.
理由:
覆盖本质上意味着将在运行时调用Base类方法或Derived类方法,具体取决于指针指向的实际对象.
它意味着:
ie:"可以通过调用Derived类方法替换可以调用Base类方法的每个实例,而无需对调用代码进行任何更改."
如果上述规则不存在,它将留下一个窗口,通过添加新功能(新派生类)来破坏现有代码.
如果在派生类中有一个函数原型,它与基类虚函数wrt参数不同,那么该函数不会覆盖基类函数,因为上面的规则被破坏了.
但是,Covariant返回类型不会破坏此规则,因为向上隐式发生并且Base类指针始终指向派生类对象而不进行任何转换,因此Standard在返回类型上强制执行协变返回类型的这种条件.
错误非常明确:你需要void Run(A*)在班上ExtendedB,但你没有.你所拥有的只是void Run(ExtendedA*),但那不一样:基类承诺接受任何 A -pointer,但你ExtendedB::Run更挑剔,只接受一个狭窄的子集.
(你很混淆协方差和逆变,但这与C++无关,因为C++不允许反变量覆盖.)