在虚函数中使用子类类型参数

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在返回类型上强制执行协变返回类型的这种条件.

  • 对于该规则,参数不需要匹配100%.虽然*协变参数*会破坏该规则,*contra变量*参数不会破坏它(可以传递给基类的每个参数也可以传递给派生类型),也不允许它们.部分原因是x-variance不是免费的,必须由修复返回参数的trampoline/thunks处理(在协方差的情况下).允许参数中的反演方差将极大地(指数地)增加所需的蹦床函数数量和虚拟表的大小. (2认同)

Ker*_* SB 9

错误非常明确:你需要void Run(A*)在班上ExtendedB,但你没有.你所拥有的只是void Run(ExtendedA*),但那不一样:基类承诺接受任何 A -pointer,但你ExtendedB::Run更挑剔,只接受一个狭窄的子集.

(你很混淆协方差和逆变,但这与C++无关,因为C++不允许反变量覆盖.)