C++对象模型
读 C++对象模型 总结
1. 类对象
内存结构:数据成员按声明顺序排列
1 class B { 2 public: 3 int bm1; 4 protected: 5 int bm2; 6 private: 7 int bm3; 8 static int bsm; 9 void bf(); 10 static void bsf(); 11 typedef void* bpv; 12 struct N { }; 13 };
2. 单继承
内存结构:先基类,后自己
1 class C { 2 int c1; 3 void cf(); 4 };
1 class D : C { 2 int d1; 3 void df(); 4 };
3. 多重继承
内存结构:先基类(基类按从左往右的顺序排列),后自己
1 class C { 2 int c1; 3 void cf(); 4 };
1 class E { 2 int e1; 3 void ef(); 4 };
1 class F : C, E { 2 int f1; 3 void ff(); 4 };
4. 虚继承
内存结构:引入vbptr,先自己,后基类
1 class C { 2 int c1; 3 void cf(); 4 };
1 class G : virtual C { 2 int g1; 3 void gf(); 4 };
注:
在VC++ 中,对每个虚继承自基类的实例,将增加一个隐藏的 vbptr(虚基类表指针)成员变量,从而达到间接计算虚基类位置的目的。该变量指向一个全类共享的偏移量表,表中项目记录了对于该类而言,vbptr 与类之间的偏移量。
GdGvbptrG(In G, the displacement of G’s virtual base pointer to G)意思是:在G中,G对象的指针与G的虚基类表指针之间的偏移量,在此可见为0,因为G对象内存布局第一项就是虚基类表指针; GdGvbptrC(In G, the displacement of G’s virtual base pointer to C)意思是:在G中,C对象的指针与G的虚基类表指针之间的偏移量,在此可见为8。
5. 菱形继承
内存结构:先父类,然后自己,最后基类
1 class C { 2 int c1; 3 void cf(); 4 };
1 class G : virtual C { 2 int g1; 3 void gf(); 4 };
1 class H : virtual C { 2 int h1; 3 void hf(); 4 };
1 class I : G, H { 2 int i1; 3 void _if(); 4 };
6. 虚函数
内存结构:引入vfptr
1 P { 2 int p1; 3 void pf(); // new 4 virtual void pvf(); // new 5 };
注:
一个vfptr被加入到类中,该vfptr指向类的虚函数表(vftable)。类中每个虚函数在该类的虚函数表中都占据一项。每项保存一个对于该类适用的虚函数的地址。因此,调用虚函数的过程如下:取得实例的vfptr;通过vfptr得到虚函数表的一项;通过虚函数表该项的函数地址间接调用虚函数。 也就是说,在普通函数调用的参数传递、调用、返回指令开销外,虚函数调用还需要额外的开销。
7. 覆盖成员函数
内存结构:引入vfptr,先基类,后自己
1 P { 2 int p1; 3 void pf(); // new 4 virtual void pvf(); // new 5 };
1 Q : P { 2 int q1; 3 void pf(); // overrides P::pf 4 void qf(); // new 5 void pvf(); // overrides P::pvf 6 virtual void qvf(); // new 7 };
注:
覆盖是静态(根据成员函数的静态类型在编译时决定)还是动态(通过对象指针在运行时动态决定),依赖于成员函数是否被声明为 “ 虚函数 ” 。
对于非虚函数来说,调用哪个成员函数是在编译时,根据 “ -> ” 操作符左边指针表达式的类型静态决定的。特别地,即使theP指向Q的实例,theP->pf()调用的仍然是P::pf(),因为theP被声明为 P* 。
对于虚函数来说,调用哪个成员函数在运行时决定。不管 “ -> ” 操作符左边的指针表达式的类型如何,调用的虚函数都是由指针实际指向的实例类型所决定 。比如,尽管theP的类型是 P* ,当theP指向Q的实例时,调用的是Q::pvf()。
8. 多重继承下的虚函数
内存结构:引入vfptr,先基类,后自己
1 class P { 2 int p1; 3 void pf(); // new 4 virtual void pvf(); // new 5 };
1 class R { 2 int r1; 3 virtual void pvf(); // new 4 virtual void rvf(); // new 5 };
1 class S : P, R { 2 int s1; 3 void pvf(); // overrides P::pvf and R::pvf 4 void rvf(); // overrides R::rvf 5 void svf(); // new 6 };
9. 虚继承下的虚函数
内存结构:引入vfptr,引入vbptr,先自己,后基类
1 class P { 2 int p1; 3 void pf(); // new 4 virtual void pvf(); // new 5 };
1 class T : virtual P { 2 int t1; 3 void pvf(); // overrides P::pvf 4 virtual void tvf(); // new 5 }; 6 7 void T::pvf() { 8 ++p1; // ((P*)this)->p1++; // vbtable lookup! 9 ++t1; // this->t1++; 10 }
内存结构:引入vfptr,引入vbptr,先基类,后自己
1 class U : T { 2 int u1; 3 };