即使没有子类覆盖它,也会虚拟调用一个方法吗?

You*_*008 6 c++ virtual call

想象一下,您有以下课程:

class A {
  public:
    virtual void print()           { printf("A\n"); }
};
class B : public A {
  public:
    virtual void print() override  { printf("B\n"); }
};
class C : public B {
    // no override of print
};
Run Code Online (Sandbox Code Playgroud)

现在,如果您创建B的实例并调用print:

B * b = new B;
b->print();
Run Code Online (Sandbox Code Playgroud)

这个方法会被虚拟调用吗?换句话说,在编译时或运行时确定要调用的确切方法?

从理论上讲,它可以在编译时确定,因为我们知道,B的子类都不会覆盖该方法,所以无论我分配到指向B的指针B * b = new C; b->print();,它总是会调用B::print().

编译器是否也知道它并使我免于虚拟调用的不必要开销?

das*_*ght 3

理论上它可以在编译时确定,因为我们知道,B 的任何子类都不会重写该方法

一般情况下,您无法在编译时确定这一点,因为 C++ 编译器一次处理一个翻译单元。例如,来自不同翻译单元的类class D : public B可以重写该方法。然而,编译器可能看不到翻译class D调用时的翻译单元b->print(),因此编译器必须假设虚拟调用。

为了解决这个缺点,C++11 引入了final关键字,它可以让程序员告诉编译器从继承层次结构的这个级别向下不会有进一步的重写。现在,编译器可以优化虚拟调用,并且还强制要求不再进行重写。