为什么派生类必须重新定义重写的基类方法

why a derived class must redefine an overrided base class method

本文关键字:定义 重写 类方法 基类 派生 新定义 为什么      更新时间:2023-10-16

我不明白为什么我需要重新定义一个覆盖的基类方法。

这里,如果我在派生类中注释foo()方法,它不会编译。

谢谢你的解释。

class Base {
public:
    void foo() {
    }
};
class Derived: public Base {
public:
#define compile_ok
#ifdef compile_ok
    // if this method is commented, it does not compile
    void foo() {
        Base::foo();
    }
#endif
    void foo(int i) {
    }
    void test() {
        foo();
        foo(1);
    }
};
void testOverride() {
    Derived d;
    d.test();
}

您的foo声明采用单个int参数将隐藏Base中命名为foo的任何函数。您可以从Base中添加一个隐藏的名称,如下所示:

class Derived: public Base {
public:
    using Base::foo; // Pulls foo from Base
    void foo(int i) {
    }
    void test() {
        foo();
        foo(1);
    }
};

您的foo(int) 隐藏了基类名称。像这样修复:

class Derived: public Base {
public:
    using Base::foo;
    void foo(int i) {
    }
    void test() {
        foo();
        foo(1);
    }
};

答案,正如其他人已经说过的那样,是派生类型中的foo隐藏了基类型中的 foo。扩展一下这意味着什么,问题是查找有一组规则,编译器必须应用这些规则,直到找到标识符。一旦它找到了这个名字,它就不会继续寻找更好的匹配,它会尝试使用它所看到的。

当在Derived::test中输入foo()时,编译器必须解析foo,它可以是任何类型(类型,[member]变量,[member]函数…)。为此,它开始查找Derived::test内部可用的内容,并且那里没有声明foo。然后将搜索范围扩大到完整类型Derived,并发现存在一个成员函数foo。此时,它停止*。如果没有找到Derived::foo(int),它将继续扩展搜索到基,然后是命名空间,然后是其他命名空间…

*在这种特殊情况下,由于标识符解析为一个函数,因此ADL启动时会采取额外的步骤(或者更确切地说,如果有非基本类型的参数传递给函数,则会启动)。