关于c ++:虚方法仅适用于基类指针

Virtual method only works for base class pointers

本问题已经有最佳答案,请猛点这里访问。

下面是C++中一个最简单的虚拟函数示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

class A {
public:
    virtual void f() {
        std::cout <<"A";
    }
};

class B : public A {
public:
    void f() {
        std::cout <<"B";
    }
};


int main() {
    {
        // calls f() in derived class
        A* a = new B();
        a->f();
    }
    {
        // calls f() in base class
        A a = B();
        a.f();
    }
}

这个程序的输出是BA。我希望它是BB,即在任何情况下都调用基类。为什么在这里使用基类指针会有所不同?我在标准中找不到解释。


这叫做切片。A a = B();创建一个类型为A的副本。关于其来源的所有信息都被遗忘了。利用多态性的唯一方法是通过引用或指针(或者允许编译时多态性的机制,例如模板或函数重载)。


多态性适用于指针,因为在指针(或引用)的情况下,可以区分指针的类型和对象的类型。现在在下面的代码中:

1
2
A a = B();
a.f();

发生的事情叫做切片。例如,对象b()被切片,其基a()被分配给a。

别忘了将析构函数设为虚拟的!


A a = B()的情况下,函数调用的顺序是:

  • 调用类B的默认构造函数。
    • 在堆栈上创建B类型的临时对象。
  • 调用从B到A的转换运算符。
    • 在堆栈上创建A类型的临时对象。
  • 使用上一个对象的地址作为参数调用类A的复制构造函数。
    • 在堆栈上创建A类型的非临时对象。
    • 此对象将保留在堆栈中,直到函数返回。
    • 它是A类型的对象,因此您得到的是"A"而不是"B"。
  • 总而言之,这里是上面这行的"完整版本":A(B()->operator A())