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

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

1 http://www.cnblogs.com/boota/p/4040310.html
2 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 A
23 {
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
~A
END0
15
31
8
12

flag=1;

~B
~A
END0
4069160
31
8
12

flag=2;

B:f()
END0
15
31
8
12

分析:

说实话,自己在这里真不知道该怎么分析了。于是在程序最后面加了一个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 A
23 {
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
~A
END0
15
31
8
12
~A

flag=1

~B
~A
END0
3807016
31
8
12
[段错误]

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

flag=2;

B:f()
END0
15
31
8
12
~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时,这里就皆大欢喜了。没什么可说的。

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

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

 

转载于:https://www.cnblogs.com/boota/p/4045320.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值