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时,这里就皆大欢喜了。没什么可说的。

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

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

 

时间: 2024-08-30 08:04:40

c++对象内存模型之虚析构函数篇(3)的相关文章

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

看了两篇关于c++对象内存模型的文章,来源在这里: http://blog.csdn.net/haoel/article/details/3081328/ http://blog.csdn.net/haoel/article/details/3081385 文章中讲了多种继承模式中虚函数的实际情况,按我的理解是把单一继承理解好了,其它几种只是一种变种.当然没这文章,我断想不到c++对象内存是这个样子. 文章中讲的情况,唯独没有讲有虚析构函数存在的情形.我学着文章中介绍的方法,用试探的方式找有虚析

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

现在讨论第二种情况: (第一种情况传送门,单独一个类,有虚析构函数,虚函数) (2)有继承关系,单一继承,父类无虚析构函数,子类有(子类没有就没必要说了) 这种情况让我相当晕,照例先贴代码 : 1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 int ia; 7 public: 8 A ():ia(15) 9 { 10 } 11 ~A () 12 { 13 cout << "~A" &l

c++ 之 内存模型:虚函数篇

一.虚函数 1.虚函数表位置分析 类:有虚函数,这个类会产生一个虚函数表 类的对象:有一个指针(vptr)会指向类的虚函数表——虚函数表指针.(位置可能在类内存空间的开头,也可能在末尾,具体由编译器实现决定) 2.继承关系作用下虚函数的手工调用 拿到虚函数表的地址,通过定义函数指针并赋值的方式可以直接调用虚函数.子类的虚函数会覆盖父类的虚函数. 3.虚函数表分析 (1)一个类只有包含虚函数才会存在虚函数表,同属于一个类的对象共享虚函数表,但拥有各自的虚函数表指针(vptr).当然所有的该类对象的

C++对象内存模型2 (虚函数,虚指针,虚函数表)

从例子入手,考察如下带有虚函数的类的对象内存模型: 1 class A { 2 public: 3 virtual void vfunc1(); 4 virtual void vfunc2(); 5 void func1(); 6 void func2(); 7 virtual ~A(); 8 private: 9 int m_data1, m_data2; 10 }; 11 12 class B : A { 13 public: 14 virtual void vfunc1();; 15 vo

(转)c#对象内存模型

对象内存模型 C#的对象内存模型写这篇博客的主要目的是为了加深自己的理解,如有不对的地方,请各位见谅. C#的对象内存模型: 一.栈内存和堆内存1.栈内存 由编译器自动分配和释放,主要用来保存一些局部变量.函数的参数等,例如,int a = 10 ,那么编译器会自动在栈上开辟一块内容用来存储变量a.2.堆内存 由程序员手动申请和释放,在C++中,通过new关键字申请,编译器不会释放,必须通过delete释放,对于C#,通过new 关键字申请,因为编译器的垃圾回收机制,程序员不需要手动释放内存.例

C#的对象内存模型

转载自:http://www.cnblogs.com/alana/archive/2012/07/05/2577893.html C#的对象内存模型: 一.栈内存和堆内存1.栈内存 由编译器自动分配和释放,主要用来保存一些局部变量.函数的参数等,例如,int a = 10 ,那么编译器会自动在栈上开辟一块内容用来存储变量a.2.堆内存 由程序员手动申请和释放,在C++中,通过new关键字申请,编译器不会释放,必须通过delete释放,对于C#,通过new 关键字申请,因为编译器的垃圾回收机制,程

C++对象内存模型1(堆栈模型)

对象内存模型 一. 栈(Stack) VS. 堆(heap) 栈 由系统自动管理,以执行函数为单位 空间大小编译时确定(参数+局部变量) 函数执行时,系统自动分配一个stack 函数执行结束时,系统立即自动回收stack 堆  在c++中由程序员手动控制 手动分配new和malloc 手动释放delete和free 具有全局性,总体无大小限制 容易造成内存泄露 1. Myclass c(10); // 栈对象,空间大小在编译时确定,函数执行结束,系统立即回收 2. Myclass* func()

C++/C#中堆栈、对象内存模型、深浅拷贝、Array.Clone方法

转载自:http://blog.csdn.net/jarvischu/article/details/6425534 目录 1.      C++/C#中对象内存模型..................................................................................................... 1 1.1.       栈内存与堆内存.............................................

极客班直播课笔记1 C++对象内存模型(堆栈模型)

对象内存模型 一. 栈(Stack) VS. 堆(heap) 栈 由系统自动管理,以执行函数为单位 空间大小编译时确定(参数+局部变量) 函数执行时,系统自动分配一个stack 函数执行结束时,系统立即自动回收stack 堆  在c++中由程序员手动控制 手动分配new和malloc 手动释放delete和free 具有全局性,总体无大小限制 容易造成内存泄露 1. Myclass c(10); // 栈对象,空间大小在编译时确定,函数执行结束,系统立即回收 2. Myclass* func()