当我这样写时:
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/