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

Posted

技术标签:

【中文标题】为啥基类指针指向基类中的纯虚方法,而不是派生类中的覆盖方法?【英文标题】:Why does the base class pointer point to the pure virtual method in the base class instead of the overidden method in the derived class?为什么基类指针指向基类中的纯虚方法,而不是派生类中的覆盖方法? 【发布时间】:2020-08-06 20:49:48 【问题描述】:
#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;

如果Foo 的构造函数引用B 的对象,那么这个程序会按照我期望的方式执行,即a_ptr-&gt;foo() 调用B::foo()

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

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

Foo: 0x7fffe90a24e0      1B
B: 10

示例输出(按值传递):

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

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

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

我想这与AVTABLE 有关,但我不能完全确定。

【问题讨论】:

Object slicing? 我可能关闭了这个错误。你把Foo (B&amp; x) a_ptr = &amp;x; 改成Foo (B x) a_ptr = &amp;x; 了吗? 我不认为这是对象切片,它是一个指向临时对象的指针 请发帖minimal reproducible example。到目前为止,您只发布了不存在您所描述问题的代码。 显示无效的代码,而不是有效的代码。 【参考方案1】:

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

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

因此,Foo::dummy() 中对a_ptr-&gt;foo() 的调用实际上是未定义的行为,因为a_ptr 一开始甚至没有指向有效对象。但是,它并没有真正崩溃,因为A::foo() 没有使用它的this 指针做任何事情。它只是指向一个编译器定义的函数,该函数会引发 pure virtual method called 错误,而您没有捕捉到该错误,因此您的程序会终止。

【讨论】:

【参考方案2】:

您通过引用 A* 类型的 a_ptr 分配了临时对象 B。在构造函数退出时,此临时对象已被销毁。由于 VTABLE 也被销毁,称为 A::foo,它是纯虚拟的。所以你明白了。

【讨论】:

以上是关于为啥基类指针指向基类中的纯虚方法,而不是派生类中的覆盖方法?的主要内容,如果未能解决你的问题,请参考以下文章

抽象类中的纯虚函数,返回类型为基/派生类型

在基类中存储指向派生类函数的指针

使用具有指向派生类对象的指针的基类指针数组调用派生类方法

使用基类中的函数静态调用纯虚函数的派生类实现

抽象类

派生自抽象基类并调用另一个类中的方法的 C++ 包装类,该类也派生自抽象基类