C++继承中的内存布局阅读笔记
2010-12-22 15:26
489 查看
2010-12-231.以字母类为例:
输出结果为:
C->0012ff58
B->0012ff5c
A->0012ff58
说明A和C指向同一位置,B和其相差4字节(一个int型的空间)。
VC++ 按照基类的声明顺序 先排列基类实例数据,最后才排列派生类数据。当然,派生类数据本身也是按照声明顺序布局的.
2.virtual继承
我们可以得到如下关于VC++虚继承下内存布局的结论:
1 首先排列非虚继承的基类实例;
2 有虚基类时,为每个基类增加一个隐藏的vbptr,除非已经从非虚继承的类那里继承了一个vbptr;
3 排列派生类的新数据成员;
4 在实例最后,排列每个虚基类的一个实例。
3.vritual 变量地址的访问
虚继承: 当类有虚基类时,访问非虚基类的成员仍然是计算固定偏移量的问题。然而,访问虚基类的成员变量,开销就增大了 , 因为必须经过如下步骤才能获得成员变量的地址:
1. 获取“虚基类表指针”;
2. 获取虚基类表中某一表项的内容;
3. 把内容中指出的偏移量加到“虚基类表指针”的地址上。
4.虚函数是动态联编的基础,虚函数是成员函数,且为非static的成员函数。
如果某类中的一个成员函数被说明为虚函数,就意味着该成员函数在派生类中可能有不同的定义,就是我们常说的重定义。(这里要注意区分三个概念,一个是重载,一个是重定义,一个是重写)当使用这个成员函数操作指针或引用所标识的对象时,将对该成员函数调用采取动态联编方式,即在运行的时候进行关联或者束定。
动态联编只能通过指针或者引用标志对象来操作虚函数,如果采用一般类型的标志对象来操作虚函数,则将采用静态联编的方式来调用虚函数。
5.
class A { public: int a; }; class B { public: int b; }; class C:public A, public B { public: int c; }; void main() { C c; void *p1=(void *)&c;//此处将c对象的地址转换为void类型的指针方便比较 void *p2=(void *)(B *)&c;//先将其转换为B类型指针在转换为void类型,便于比较 void *p3=(void *)(A *)&c;//同上。 cout<<p1<<endl; cout<<p2<<endl; cout<<p3<<endl; cout<<sizeof(c)<<endl; }
输出结果为:
C->0012ff58
B->0012ff5c
A->0012ff58
说明A和C指向同一位置,B和其相差4字节(一个int型的空间)。
VC++ 按照基类的声明顺序 先排列基类实例数据,最后才排列派生类数据。当然,派生类数据本身也是按照声明顺序布局的.
2.virtual继承
我们可以得到如下关于VC++虚继承下内存布局的结论:
1 首先排列非虚继承的基类实例;
2 有虚基类时,为每个基类增加一个隐藏的vbptr,除非已经从非虚继承的类那里继承了一个vbptr;
3 排列派生类的新数据成员;
4 在实例最后,排列每个虚基类的一个实例。
3.vritual 变量地址的访问
虚继承: 当类有虚基类时,访问非虚基类的成员仍然是计算固定偏移量的问题。然而,访问虚基类的成员变量,开销就增大了 , 因为必须经过如下步骤才能获得成员变量的地址:
1. 获取“虚基类表指针”;
2. 获取虚基类表中某一表项的内容;
3. 把内容中指出的偏移量加到“虚基类表指针”的地址上。
4.虚函数是动态联编的基础,虚函数是成员函数,且为非static的成员函数。
如果某类中的一个成员函数被说明为虚函数,就意味着该成员函数在派生类中可能有不同的定义,就是我们常说的重定义。(这里要注意区分三个概念,一个是重载,一个是重定义,一个是重写)当使用这个成员函数操作指针或引用所标识的对象时,将对该成员函数调用采取动态联编方式,即在运行的时候进行关联或者束定。
动态联编只能通过指针或者引用标志对象来操作虚函数,如果采用一般类型的标志对象来操作虚函数,则将采用静态联编的方式来调用虚函数。
5.
class A { public: virtual void print(){cout<<"A"<<endl;} void print_1(){cout<<"print_1 in A"<<endl;} }; class B:public A { public: void print(){cout<<"B"<<endl;} void print_2(){cout<<"print_2 in B"<<endl;} }; void print(A *a) { a->print(); } void main() { A a; A *pa=&a; B b; B *pb=&b; A *pab=pb;//此处用A类型的指针指向了B的对象,若print()没有声明为虚函数,则编译时调用哪个print函数由->符号左边来决定.若声明为虚函数,则调用由指针实际指向的类型决定. pab->print();//若print非虚函数,则输出A,若声明为虚函数,则输出B. }
相关文章推荐
- 【C++】c++单继承、多继承、菱形继承内存布局(虚函数表结构)
- c++继承中的内存布局(转)
- 转载:C++ 多继承和虚继承的内存布局
- C++对象模型笔记:对象实例内存布局的小小结
- c++继承下的内存布局
- C++ 多继承和虚继承的内存布局
- C++对象模型:多重继承和虚继承的内存布局
- c++继承中的内存布局
- 【C++】菱形虚拟继承(内存布局)
- c++继承中的内存布局(转载)
- C++ 多继承和虚继承的内存布局
- c++继承中的内存布局
- c++一般继承内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- Linux Debugging(四): 使用GDB来理解C++ 对象的内存布局(多重继承,虚继承)
- 从汇编看c++中的虚拟继承及内存布局(二)
- C++ 对象的内存布局—— 虚继承下的虚函数
- C++ 对象的内存布局(单继承)
- C++ 内存布局(二) 虚继承 ---Empty virtual base classs (空虚基类)