重写返回基类型的函数

Override function that return base type

本文关键字:函数 类型 基类 返回 重写      更新时间:2023-10-16

我有两个类。基类CCD_ 1和派生类CCD_。类Parent具有返回其类类型的纯虚拟函数。如何在派生类中重写它?

class Parent
{
    public:
        virtual Parent* OverrideMe(Parent* func) = 0;
};
class Child : public Parent
{
    public:
        Child* OverrideMe(Child* func) override;
};

我尝试了Child* OverrideMe(Child* func) override;,但最终出现了一个错误,即它没有覆盖基类成员。

如果C++有完全的协方差和逆变支持,正确的关系将是输入中的逆变和输出中的协变。即:

struct Organism { };
struct Animal : Organism {
    virtual Animal* OverrideMe(Animal* ) = 0;
};
struct Dog : Aniaml {
    Dog* OverrideMe(Organism* ) override { ... }
    ↑↑↑             ↑↑↑↑↑↑↑↑
    covariant       contravariant
};

这看起来有点不直观,但确实有道理。如果您期望一个Animal*,那么您应该能够处理任何属于Animal*Dog*符合条件)的内容。相反,如果你在Animal*上做一些运算,你只需要一个可以取Animal*的运算,而取Parent0的运算在这方面是合格的。

请注意,如果输入是co变体,则会破坏类型系统。考虑类似的事情;

Animal* a = new Dog;
a->OverrideMe(new Cat);

如果Dog::OverrideMe被允许接受Dog*,那将失败——Cat*不是Dog*!所以可以乘坐Animal*。。。或者任何比这更通用的东西(例如Organism*),因为所有这些都可以正常工作。

C++不支持输入中的逆变,只支持输出中的协方差。所以你可以写:

Dog* OverrideMe(Animal* ) override { ... }

或:

Animal* OverrideMe(Animal* ) override { .... }

但没有别的。

函数参数的类型和函数的cv限定符必须相同。所以你可以使用

Child* OverrideMe(Parent* func) override;

您没有在这里重写,因为您的OverrideMe函数与您试图重写的基类中的函数不接受相同的参数:

class Parent
{
    public:
        virtual Parent* OverrideMe(Parent* func) = 0;
};
class Child : public Parent
{
    public:
        virtual Child* OverrideMe(Parent* func) override;
};

这"闻起来很臭",换句话说,你正在"打破"正常的"任何对象都应该被派生的任何其他对象替换"。

如果基类中有一个接口函数,那么该函数在整个类层次结构中应该采用相同的类型。

所以正确的做法是:

Parent*OverrideMe(Parent*func)覆盖;

(正如juancopanza所说,你可以返回一个派生类型,但你确定父返回的值总是同一个类吗?对我来说,这看起来像是可能返回"任何派生对象"的函数类型,在这种情况下,你要么撒谎,要么得到"有趣的效果")

如果由于某种原因,这在您的情况下实际上不起作用,那么您可能不应该以这种方式使用继承。