#include<iostream>
using namespace std;
class A
{
public:
int i;
A() {cout<<"A()"<<endl;}
~A() {cout<<"~A()"<<endl;}
};
class B:public A
{
public:
int j;
B(): j(10)
{
this->i=20;
this->~A();
}
};
int main()
{
B abc;
cout<<"i="<<abc.i<<" j="<<abc.j<<endl;
}//main
两个问题:
有没有办法在B的构造函数中为A创建一个初始化列表?像这样:
class B:public A
{
B(): j(10), A():i(20) {}
};
答案 0 :(得分:5)
class A()
构造函数,如下所示:B(): A( .. ), ...
A* a = new B();
//..
delete a;
除非class A
析构函数是虚拟的,否则将不调用B的析构函数。这就是为什么不应该派生STL容器 - 他们的析构函数不是虚拟的。
答案 1 :(得分:5)
析构函数与您可以调用的任何其他常规函数一样(但除非您使用新的展示位置,否则不应该这样做)。当您在对象上调用delete
时,会发生两件事情:调用析构函数进行清理,然后调用operator delete
来释放为该对象分配的内存。这里第二步没有发生。
不,你不能这样称呼它。你可以做的是这样的事情:
A班 { 上市: A(int n):i(n){} };
B类:公众A { 上市: B():A(20),j(10){} };
答案 2 :(得分:3)
要点:
维基百科上的第1点):
没有虚拟析构函数,而 删除B类的实例 正确地为两个B调用析构函数 如果对象被删除,则为A. B的实例,B的实例 通过指向其基础的指针删除 A类将产生未定义的 行为。
示例(针对第2点):
B(): A(), j(10) {}
或
B(): A() {j = 10;}
答案 3 :(得分:3)
@Nav:不,你对“被摧毁”的理解是错误的。调用对象的析构函数时,对象将被销毁。你似乎相信它所存在的记忆完全蒸发,但这种情况从未发生过。该对象不再存在,但是对象通常会遗留一些垃圾数据,如果您愿意违反C ++的规则并调用未定义的行为,那么您可以读取剩余的字节,并且它们将看起来像对象,并且由于没有运行时检查您是否正在访问有效对象,您通常可以将它们视为对象。你做了什么。
这是非法的,它是未定义的行为,但在实践中它通常有效。
再一次,析构函数不会物理地蒸发内存。析构函数执行后,您的RAM仍具有相同的容量。从概念上讲,一旦析构函数运行,该对象就不再存在。但它所包含的数据仍在记忆中。
答案 4 :(得分:2)
1)C ++中的析构函数调用顺序与构造函数调用顺序的顺序相反。所以首先派生类对象得到破坏,然后是基类对象。
2)否。
答案 5 :(得分:2)
在您提供的代码中,您确实正在销毁基类,因此i
。调用析构函数然后使用死对象是未定义的行为 - 它可能有效或可能崩溃。
i
应该是int
(例如vector
)更复杂的东西,尝试对此做任何事情都可能导致崩溃。
答案 6 :(得分:2)
如果你自己调用〜SomeClass(),显式地调用析构函数。这使得对象(在这种情况下,对象的基类部分)处于被破坏状态。
由于析构函数不是虚拟的,因此不会调用派生类的析构函数,但也会销毁SomeClass的基类。
试图通过仅使用i成员来确定A是否真的被破坏,这不是一个好的测试。实际上,您无法对此进行测试,因为使用该对象会导致未定义的行为。它可能有用,或者它可能没有(在你的情况下,它可能会打印“i = 20 j = 10”,但我已经被销毁了。)