派生类与基类的类型兼容性会导致内存泄漏吗?
我知道派生类与其基类的指针类型兼容。在给定的示例代码中,new bar
对象构造是通过调用 foo::foo()
进行的,然后调用 bar::bar()
。在各自的构造函数中,我将资源分配给类成员 foo::int *a
和 bar::int *b
。
现在我将由此构造的对象初始化为基类类型。使用 obj,我可以调用基类析构函数,但不能调用派生类析构函数。那么,在这种情况下如何释放派生类资源呢?这不是内存泄漏吗?
#include <iostream>
class foo
{
int *a;
public:
foo()
{
a = new int[5];
std::cout << "\n foo constructor" << std::endl;
}
~foo()
{
std::cout << "\n foo destructor" << std::endl;
delete[] a;
}
};
class bar : public foo
{
int *b;
public:
bar()
{
b = new int[5];
std::cout << "\n bar constructor" << std::endl;
}
~bar()
{
std::cout << "\n bar destructor" << std::endl;
delete[] b;
}
};
int main()
{
foo *obj = new bar; // Derived class object is type compatible with base class
delete obj; // Equivalent to obj->~foo();
return 0;
}
谢谢。
I understand that derived class is type compatible with a pointer to its base class. In the given sample code, new bar
object construction takes place calling foo::foo()
followed by bar::bar()
. In the respective constructors, I am allocating resources to class members foo::int *a
and bar::int *b
.
Now I am initializing thus constructed object to base class type. With obj
, I can call the base class destructor but not the derived class destructor. So, how can I deallocate the derived class resources in this case? Is this not a memory leak ?
#include <iostream>
class foo
{
int *a;
public:
foo()
{
a = new int[5];
std::cout << "\n foo constructor" << std::endl;
}
~foo()
{
std::cout << "\n foo destructor" << std::endl;
delete[] a;
}
};
class bar : public foo
{
int *b;
public:
bar()
{
b = new int[5];
std::cout << "\n bar constructor" << std::endl;
}
~bar()
{
std::cout << "\n bar destructor" << std::endl;
delete[] b;
}
};
int main()
{
foo *obj = new bar; // Derived class object is type compatible with base class
delete obj; // Equivalent to obj->~foo();
return 0;
}
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这就是“虚拟析构函数”的想法出现的地方。从技术上讲,如果通过基类类型的指针删除一个对象,则必须将该基类析构函数标记为虚拟,否则结果是未定义的。如果你确实将析构函数标记为virtual,则其含义与其他虚函数不同。它的意思不是“派生类重写此行为”,而是“通过基类指针删除此对象时,在调用基类构造函数之前调用派生析构函数”。这就是您想要的行为。
作为一般规则,您定义的任何计划子类化的类都应该有一个虚拟析构函数来防止此类问题。
This is where the idea of the "virtual destructor" comes in. Technically speaking, if you delete an object through a pointer of a base class type, you must mark that base class destructor virtual or the result is undefined. If you do mark the destructor virtual, the meaning is different from other virtual functions. Instead of meaning "derived classes override this behavior," it means "when deleting this object through a base class pointer, call the derived destructors before calling the base constructor." This is the behavior you want.
As a general rule, any class you define that you plan on subclassing should have a virtual destructor to prevent this sort of problem.
如果您通过指向其基类之一的指针
删除
派生类对象,则基类析构函数必须声明为虚拟
,否则行为未定义。如果
~foo()
被声明为virtual
,那么就可以开始了。首先调用~bar()
,然后调用~foo()
。If you
delete
a derived class object via a pointer to one of its base classes, the base class destructor must be declaredvirtual
, otherwise the behavior is undefined.If
~foo()
is declaredvirtual
, you're good to go.~bar()
will be called first, then~foo()
.这实际上是一种未定义的行为。
来自标准文档。 5.3.5.3 删除,
It is actually an undefined behavior.
From Standard docs. 5.3.5.3 Delete,
执行此操作,
这可确保执行
delete *pFoo
也会调用派生类析构函数 (~bar()
)。调用顺序为~bar()
,后跟~foo()
。如果您对
~bar()
也做同样的事情也会很好,也就是说,尽管如果您不想进一步从
bar 派生,那么对于这种情况来说这并不是那么必要
并希望将bar*
用于它的派生类。Do this,
This ensures that doing
delete *pFoo
also invokes derived classes destructor (~bar()
). The order of invocation would be~bar()
followed by~foo()
.It will also be good if you do the same for
~bar()
also, that is,Although it's not that much necessary for this scenario if you don't want to further derive from
bar
and want to usebar*
for it's derived classes.