首页 > 代码库 > c++对象内存模型之虚析构函数篇(3)

c++对象内存模型之虚析构函数篇(3)

经过前两篇的分析,说实话, 现在的我是比较晕的。但仍然坚持自己的学习方法,先自己“理所当然”的理解,再去求证官方说法。毕竟东西是别人定的,规则是别人的。

1 http://www.cnblogs.com/boota/p/4040310.html2 http://www.cnblogs.com/boota/p/4043282.html

这次是讨论的情形是:有继承关系,单一继承,父类有虚析构函数。(子类有没有虚析构函数不影响,这个结论可以验证,就不另做讨论)

上代码:

 1 #include <iostream> 2 using namespace std; 3  4 class A 5 { 6 public: 7        int ia; 8   9        A ():ia(15)10      {        11       } 12      virtual ~A ()13      {14            cout << "~A" << endl;15      } 16      virtual void f()17      {18           cout << "A:f()" <<endl;19      } 20 };21 22 class B : public A23 {24        public :25        int ib;26 27       B():ib(31){}28       virtual ~B()29       {30                  cout << "~B" << endl;           31       }  32       virtual void f()33       {34                  cout << "B:f()" << endl;           35       }36        37 };38 39 typedef void (*F)();40 41 int main()42 {43 44      F pf = NULL;45     B *b = new B();46     int **p = (int **)b;47 48     int flag = 2   ;49     pf = (F)p[0][flag];50     pf();51 52     cout << "END"<<p[0][3] << endl;53     cout << b->ia << endl;54     cout << b->ib << endl;55 56     cout << sizeof(A) << endl;57     cout << sizeof(B) << endl;58 }

 程序输出 :

flag=0;

~B~AEND01531812

flag=1;

~B~AEND0406916031812

flag=2;

B:f()END01531812

分析:

说实话,自己在这里真不知道该怎么分析了。于是在程序最后面加了一个delete b,貌似得见云开见明月,貌似。。。

见代码

 1 #include <iostream> 2 using namespace std; 3  4 class A 5 { 6 public: 7        int ia; 8   9        A ():ia(15)10      {        11       } 12      virtual ~A ()13      {14            cout << "~A" << endl;15      } 16      virtual void f()17      {18           cout << "A:f()" <<endl;19      } 20 };21 22 class B : public A23 {24        public :25        int ib;26 27       B():ib(31){}28       virtual ~B()29       {30                  cout << "~B" << endl;           31       }  32       virtual void f()33       {34                  cout << "B:f()" << endl;           35       }36        37 };38 39 typedef void (*F)();40 41 int main()42 {43 44      F pf = NULL;45     B *b = new B();46     int **p = (int **)b;47 48     int flag = 2   ;49     pf = (F)p[0][flag];50     pf();51 52     cout << "END"<<p[0][3] << endl;53     cout << b->ia << endl;54     cout << b->ib << endl;55 56     cout << sizeof(A) << endl;57     cout << sizeof(B) << endl;58     delete b;59 }

输出:

flag=0

~B~AEND01531812~A

flag=1

~B~AEND0380701631812[段错误]

调试发现段错误发生在代码的58行,即delete b这句。是不是有点感觉了。

flag=2;

B:f()END01531812~B~A

这下可以写点分析了,不然冏死了。

flag=0时,先执行了虚函数表第一个元素指定的析构函数,对后面的影响是delete语句只执行了A的析构函数,这说明第一个元素是B的析构函数,尼玛,为什么数据ia,ib都没有变???理论上来说,A有虚析构函数,delete b这句是应该输出~B\n~A\n,此时由于先执行了虚函数表中第一个函数,delete只执行了A的析构函数,说明b已经退化成指向A的对象的指针。数据没变,不过数据是合法的,这个可以写个复杂点的类来验证。综上,是不是可以得出第一个析构函数,靠,不知道干嘛的,存疑。

flag=1时,就很正常了。段错误也有了,数据显示不正常,再加上输出也是执行B与A的析构函数的效果,充分说明虚函数表第二个元素就是B的析构函数。这里再猜一次,第一个是A的,或者只是一个效果,表明是A的子类,so还是不知道干嘛的。

flag=2时,这里就皆大欢喜了。没什么可说的。

所以,我们的结论就在这里停住了,貌似三个代码都表明,虚析构函数的第二个是本类的析构函数,其它等我再写个复杂点的代码,中间有指针申请空间的那种,这个在栈里玩的代码,估计是很难引起段错误。

照例内存图示画一个,如下:

 

c++对象内存模型之虚析构函数篇(3)