为什么基类指针指向基类中的纯虚方法而不是派生类中的覆盖方法?

use*_*083 1 c++ inheritance gcc run-time-polymorphism

#include <iostream>

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

class B : public A
{
    private:
        int x;

    public:
        B(int a) : x(a) {}
        void foo(void) { std::cout << "B: " << x << "\n"; }
};

class Foo
{
    private:
        A* a_ptr;

    public:
        Foo (B& x) { a_ptr = &x; }
        A* get_ptr(void) { return a_ptr; }
        void dummy(void) { std::cout << "Foo: "; std::cout << a_ptr << "\t "<< typeid(*a_ptr).name() << "\n"; a_ptr->foo(); std::cout << "\n"; }
};

int main(void)
{
        B b(10);
        Foo f(b);

        f.dummy();
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果 的构造函数Foo引用 的对象B,则该程序按照我期望的方式执行,即a_ptr->foo()调用B::foo().

但是,如果构造函数更改为按值接受参数,则a_ptr->foo()解析为A::foo(),并导致pure virtual method called exception

示例输出(通过引用传递:):

Foo: 0x7fffe90a24e0      1B
B: 10

Run Code Online (Sandbox Code Playgroud)

示例输出(按值传递):

Foo: 0x7fffc6bbab20      1A
pure virtual method called
terminate called without an active exception
Aborted (core dumped)

Run Code Online (Sandbox Code Playgroud)

我对为什么会发生这种情况有一个模糊的预感,我正在寻找一些可能证明或反驳我的假设的文献或参考资料:通过引用传递时,基类指针a_ptr指向一个生命周期超过调用a_ptr->foo().

但是,当按值传递时,a_ptr指向在构造函数退出时丢失的临时对象。

我想这与VTABLEof 有关系A,但我不能完全理解它。

Rem*_*eau 5

是的,你的怀疑是正确的。

B对象按值传递给Foo构造函数时,它就成为构造函数的局部变量。构造函数正在保存一个指向该本地对象的指针,当构造函数退出时,该指针超出范围。

因此,对a_ptr->foo()in的调用Foo::dummy()实际上是未定义的行为,因为a_ptr它甚至没有指向一个有效的对象。但是,它并没有真正崩溃,因为A::foo()它的this指针不用于任何事情。它只是指向一个编译器定义的函数,该函数抛出pure virtual method called错误,你没有发现,所以你的程序终止。