为什么基class指针指向基class中的纯虚方法,而不是派生class中的重写方法?
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?
#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)
我对为什么会发生这种情况有一种模糊的预感,我正在寻找一些可能证明或反驳我的假设的文献或参考资料:当通过引用传递时,基础 class 指针a_ptr
指向一个实体,其生命周期超过对 a_ptr->foo()
的调用。
但是,当按值传递时,a_ptr
指向一个在构造函数退出时丢失的临时文件。
我想这与 A
的 VTABLE
有关,但我不能完全确定。
是的,你的猜测是正确的。
当B
对象通过值传递给Foo
构造函数时,它成为构造函数的局部变量。构造函数正在保存指向该本地对象的指针,该对象在构造函数退出时超出范围。
因此,在 Foo::dummy()
中对 a_ptr->foo()
的调用实际上是 未定义的行为 因为 a_ptr
甚至没有指向有效对象首先。但是,它并没有真正崩溃,因为 A::foo()
没有将它的 this
指针用于任何事情。它只是指向抛出 pure virtual method called
错误的 compiler-defined 函数,您没有捕获到该错误,因此您的程序终止。
您通过引用 a_ptr 为类型 A* 分配了临时对象 B。在构造函数退出时,此临时对象已被销毁。由于VTABLE也被销毁了,称为A::foo,是纯虚的。所以你明白了。
#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)
我对为什么会发生这种情况有一种模糊的预感,我正在寻找一些可能证明或反驳我的假设的文献或参考资料:当通过引用传递时,基础 class 指针a_ptr
指向一个实体,其生命周期超过对 a_ptr->foo()
的调用。
但是,当按值传递时,a_ptr
指向一个在构造函数退出时丢失的临时文件。
我想这与 A
的 VTABLE
有关,但我不能完全确定。
是的,你的猜测是正确的。
当B
对象通过值传递给Foo
构造函数时,它成为构造函数的局部变量。构造函数正在保存指向该本地对象的指针,该对象在构造函数退出时超出范围。
因此,在 Foo::dummy()
中对 a_ptr->foo()
的调用实际上是 未定义的行为 因为 a_ptr
甚至没有指向有效对象首先。但是,它并没有真正崩溃,因为 A::foo()
没有将它的 this
指针用于任何事情。它只是指向抛出 pure virtual method called
错误的 compiler-defined 函数,您没有捕获到该错误,因此您的程序终止。
您通过引用 a_ptr 为类型 A* 分配了临时对象 B。在构造函数退出时,此临时对象已被销毁。由于VTABLE也被销毁了,称为A::foo,是纯虚的。所以你明白了。