1.类布局
1.1简单类对象的内存布局
class A { public: void f(); private: int i; char c; static int s; };
简单对象的内存布局:非静态(staic)成员变量,按照其在类中声明的顺序,加上字节对齐,依次分布在内存中。
1.2含有虚函数类对象的内存布局。
class A { public: void f(); virtual void vf(); private: int i; char c; static int s; };
带有虚函数对象的内存布局:在实例的起始内存位置放置一个4字节大小的空间用来保存虚函数表的地址。
1.3 多继承或单继承。
class A { public: void f(); virtual void vf(); private: int i; char c; static int s; }; class B :public A { public: int b; virtual void vb(); };
每个派生类的实例中都包含了一份完整的基类实例数据。
MSC++ 保证任何继承自有虚函数的类的第一项永远是vfptr,例如 class A:public B, public C 如果C含有虚函数,那么C实例在A实例的前面。
MSC++实例对象会共享或重用从基类继承来的vfptr,但是在多重继承下,一个实例可能包含多个vfptr。
MSC++中,如果派生类的某个函数覆盖了多个基类的虚函数时,这时候会使用调整块。但只是覆盖非最左的基类的虚函数时,MSC++一般不创建调整块,采用接受嵌套在派生类实例中的非最左基类的指针。
MSC++虚拟继承可能还会涉及调整块。
MSC++派生类中的新虚函数不会共用虚继承基类的虚函数表,而是新建一个虚函数表。放在实例顶端。
2.函数调用
对于非虚成员函数来说,调用哪个成员函数是在编译时,根据-> 操作符左边的指针表达式的类型静态决定;决定隐藏的this参数类型。
对于虚函数调用来说,调用的虚函数是由指针实际指向的实例类型所决定。