#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->foo()
调用B::foo()
。但是,如果将构造函数更改为按值接受参数,则
a_ptr->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->foo()
。但是,当按值传递时,
a_ptr
指向一个临时变量,该临时变量在构造函数退出时丢失。我想这与
VTABLE
的A
有关,但是我不能完全依靠它。
最佳答案
是的,您的怀疑是正确的。
当B
对象按值传递给Foo
构造函数时,它成为该构造函数的局部变量。构造函数正在保存指向该本地对象的指针,该指针在构造函数退出时会超出范围。
因此,在a_ptr->foo()
中对Foo::dummy()
的调用实际上是未定义的行为,因为a_ptr
甚至都没有指向有效的对象。但是,它并没有真正崩溃,因为A::foo()
不使用this
指针进行任何操作。它只是指向编译器定义的函数,该函数会引发pure virtual method called
错误,但您不会捕获该错误,因此程序将终止。
关于c++ - 为什么基类指针指向基类中的纯虚方法而不是派生类中的重写方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63291546/