#include <cstdio>
using namespace std;
class A {
public:
virtual void func() { printf("A::func()"); }
};
class B : public A {
public:
virtual void func() { printf("B::func()"); }
};
int main() {
A a = *(A *)new B();
a.func();
}
问题很简单:为什么 a->func()
调用类 A
中的函数,即使 a
包含类 B 的对象?
最佳答案
A a = *(A *)new B();
a.func();
这是这段代码中发生的事情,一步一步:
new B()
:一个新的 B 类型对象被分配到空闲存储区,产生它的地址(A*)
:对象的地址被转换为A*
,所以我们实际上有一个A*
类型的指针指向有效的 B 类型对象。一切顺利。A a
:问题从这里开始。 A 类型的新本地对象 在堆栈上创建并使用复制构造函数A::A(const A&)
构造,第一个参数是之前创建的对象.- 指向 B 类型原始对象的指针在此语句后丢失,导致内存泄漏,因为它是使用
new
在空闲存储上分配的。 a.func()
- 该方法在类 A 的(本地)对象上调用。
如果将代码更改为:
A& a = *( A*) new B();
a.func();
然后只会构造一个对象,它的指针将被转换为A*
类型的指针,然后取消引用并使用该地址初始化一个新的引用。虚函数的调用将动态解析为 B::func()
。
但请记住,您仍然需要释放该对象,因为它是用 new
分配的:
delete &a;
顺便说一句,只有当 A 有一个虚拟析构函数时才是正确的,这是 B::~B() 所必需的(幸运的是这里是空的,但在一般情况下不需要)也会被调用。如果 A 没有虚拟析构函数,那么您需要通过以下方式释放它:
delete (B*)&a;
如果您想使用指针,那么这与引用相同。代码:
A* a = new B(); // actually you don't need an explicit cast here.
a->func();
delete (B*)a; // or just delete a; if A has a virtual destructor.
关于c++ - C++ 中的覆盖函数不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4574321/