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" << endl;
14      }
15      virtual void f()
16      {
17           cout << "A:f()" <<endl;
18      }
19 };
20
21 class B : public A
22 {
23        int ib;
24 public :
25       B():ib(31){}
26       virtual ~B()
27       {
28                  cout << "~B" << endl;
29       }
30       virtual void f()
31       {
32                  cout << "B:f()" << endl;
33       }
34
35 };
36
37 typedef void (*F)();
38
39 int main()
40 {
41
42      F pf = NULL;
43     B *b = new B();
44     int **p = (int **)b;
45
46     int flag = 0;
47     pf = (F)p[0][flag];
48     pf();
49
50     cout << "END"<<p[0][3] << endl;
51     cout << p[1] << endl;
52     cout << p[2] << endl;
53
54     cout << sizeof(A) << endl;
55     cout << sizeof(B) << endl;
56 }

输出如下:

flag = 0;

1 B:f()
2 END0
3 0xf
4 0x1f
5 8
6 12

flag = 1;

1 ~B
2 ~A
3 END4460356
4 0xf
5 0x1f
6 8
7 12

flag = 2;

~B
~A
END1818846781
0x2c29a0
0x1f
8
12

分析:

flag=0时, B的虚函数f替代了B的虚函数f,打印输出B:f(),这个好理解。要注意的地方是,此时给flag=0,意味着,f在虚函数表的最前面,A没有虚析构函数。END后面的数也很正常。

flag=1时,输出为~B\n~A\n,从现象上来看,是先执行B的析构函数再执行A的析构函数,与常识相符。但END后面的数据与flag=0时的数据0不同,再加上B中的两个成员变量的值是对的,这个让我很难相信对象内存被释放。如果没有释放,END后面的数又很难解释。

flag=2时,输出为~B\n~A\n,成员变量输出已经算是乱码,至少说明内存被释放。ia是乱码,ib仍然是0x1f。从输出上来看,先后执行了B,A的析构函数,确认内存已被释放。由于ib仍是0x1f,我认为是内存没有更新的原因。

结论:与第一篇里说的那样,虚析构函数的第“二”个是释放内存用的,第一个仍然不知道干嘛的。其它的与文章最开始介绍的两个连接里说的一样,子类的虚函数会覆盖父类对应虚函数在虚函数表中的位置。

下面画个内存结构示意图:

A的内存结构请见第一篇文章,这里只画B的。

vptr是虚函数表的指针,图里的都好说,当然,这些全是根据现象猜的,目前来说没有去看权威资料的原因是为了真正理解,目前看自己能猜对多少。没人给我打分,怕毛。

注:类图可以用ArgoUML,内存图可以用win7自带的画图工具。

时间: 2024-10-22 20:50:39

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

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

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

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

经过前两篇的分析,说实话, 现在的我是比较晕的.但仍然坚持自己的学习方法,先自己“理所当然”的理解,再去求证官方说法.毕竟东西是别人定的,规则是别人的. 1 http://www.cnblogs.com/boota/p/4040310.html 2 http://www.cnblogs.com/boota/p/4043282.html 这次是讨论的情形是:有继承关系,单一继承,父类有虚析构函数.(子类有没有虚析构函数不影响,这个结论可以验证,就不另做讨论) 上代码: 1 #include <io

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()