c++ - 覆盖虚拟成员函数时,为什么覆盖函数总是变为虚拟?

标签 c++ inheritance virtual overriding

当我这样写的时候:

class A {
    public: virtual void foo() = 0;
}

class B {
    public: void foo() {}
}

...B::foo() 也变为虚拟的。这背后的原理是什么?我希望它的行为类似于 Java 中的 final 关键字。

补充:我知道它是这样工作的,也知道 vtable 是如何工作的:)问题是,为什么 C++ 标准委员会没有留下直接调用 B::foo() 并避免 vtable 查找的机会。

最佳答案

标准确实留下了直接调用 B::foo 并避免表查找的机会:

#include <iostream>

class A {
    public: virtual void foo() = 0;
};

class B : public A {
    public: void foo() {
        std::cout <<"B::foo\n";
    }
};

class C : public B {
    public: void foo() {
        std::cout <<"C::foo\n";
    }
};

int main() {
    C c;
    A *ap = &c;
    // virtual call to foo
    ap->foo();
    // virtual call to foo
    static_cast<B*>(ap)->foo();
    // non-virtual call to B::foo
    static_cast<B*>(ap)->B::foo();
}

输出:

C::foo
C::foo
B::foo

所以你可以得到你所说的你期望的行为如下:

class A {
    virtual void foo() = 0;
    // makes a virtual call to foo
    public: void bar() { foo(); }
};

class B : public A {
    void foo() {
        std::cout <<"B::foo\n";
    }
    // makes a non-virtual call to B::foo
    public: void bar() { B::foo(); }
};

现在调用者应该使用 bar 而不是 foo。如果他们有 C*,那么他们可以将其转换为 A*,在这种情况下 bar 将调用 C::foo,或者他们可以将其转换为 B*,在这种情况下,bar 将调用 B::foo。如果需要,C 可以再次覆盖 bar ,否则就不用管了,在这种情况下,在 C* 上调用 bar() 会调用 B::foo()期待。

不过,我不知道什么时候会有人想要这种行为。虚函数的全部意义在于为给定对象调用相同的函数,无论您使用的是什么基类或派生类指针。因此,C++ 假设如果通过基类对特定成员函数的调用是虚拟的,那么通过派生类的调用也应该是虚拟的。

关于c++ - 覆盖虚拟成员函数时,为什么覆盖函数总是变为虚拟?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1929209/

相关文章:

C++ - 希望虚拟仅作为重定向

c++ - C++中纯虚函数的实现

c++ - C++ 中 Delete 的行为

c# - 接口(interface)疑惑问题

c++ - 无法匹配函数定义、模板

c# - 在 Inherited Class Constructor C# 中强制部分基初始化(和方法)(就像抽象对方法所做的那样)——解决这个问题

c++ - std::map::operator[] 比 std::map::insert 更有效吗?

c++ - Windows 上的 DLL Main 对比。 __attribute__((constructor)) Linux 上的入口点

c++ - 第 N 个四面体数 mod m?

linux - 具有身份验证设置的 Postfix 虚拟邮箱允许从未经身份验证的用户发送邮件