【问题标题】:Virtual method only works for base class pointers [duplicate]虚拟方法仅适用于基类指针[重复]
【发布时间】:2014-01-30 20:47:09
【问题描述】:

下面可能是 C++ 中最简单的虚函数示例:

#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,即无论如何都要调用基类。 为什么在这里使用基类指针会有所不同? 我没有在标准中找到解释。

【问题讨论】:

  • 我相信这是一个与切片不同的问题。在这里,似乎是对继承、多态性和运行时分派的误解。他还错过了它同时适用于“基类指针”和“基类引用”的事实。 (并且可能还有另一个关于该主题的 SO 问题)。

标签: c++ virtual-functions


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    正在发生的事情称为切片。即对象 B() 被切片,其基 A() 被分配给 a。

    不要忘记将析构函数设为虚拟!

    【讨论】:

      【解决方案3】:

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

      1. B 类的默认构造函数被调用。
        • 在堆栈上创建了一个 B 类型的临时对象。
      2. 调用从 B 到 A 的转换运算符。
        • 在堆栈上创建了一个 A 类型的临时对象。
      3. 类 A 的复制构造函数以前一个对象的地址作为参数调用。
        • 在堆栈上创建了一个 A 类型的非临时对象。
        • 此对象将保留在堆栈中,直到函数返回。
        • 它是 A 类型的对象,因此打印的是“A”而不是“B”。

      总结一下,这里是上面那行的“完整版”:A(B()-&gt;operator A())

      【讨论】:

        猜你喜欢
        • 2011-03-20
        • 2011-09-30
        • 1970-01-01
        • 2016-10-27
        • 1970-01-01
        • 1970-01-01
        • 2010-12-29
        • 1970-01-01
        • 2013-10-13
        相关资源
        最近更新 更多