c++对象模型
1.对象的存储模型
a) 对象的构成
i. 类中包含static、nostatic成员变量和static、nostatic、virtual成员函数。在对象中仅仅存放【nostatic成员变量】和指向virtual成员函数的表的【虚表指针】以及一个【type_info对象实际类型】,static成员自然存储在全局静态区,而普通成员函数,则会以Point::float x()const{}这种形式和其他普通函数一样存储。(只不过在前面加上【类名::】,并在类中留下声明而已)
class Point{ protected: virtual ostream& print(ostream &os)const; float _x; static int point_count; public : Point(float xval); virtual ~Point(); float x()const; static int PointCount(); };
![]()
b) 加入单继承,子类对象的构成
i. 【子类虚表指针】+【从父类继承来的nostatic成员变量和成员函数声明】+【子类自己定义的nostatic成员变量】。子类的虚表是先拷贝父类的虚表,按照type_info对象实际类型修改拷贝来的虚表,然后在拷贝的虚表后面加上自己虚函数的函数地址指针
基类:对象中包含非静态变量count,对象类型typeinfo,以及含有虚函数地址表的指针vptr
Class Base{ Public: Base(int); Virtual ~Base(); Int getIBase() const; Static int instanceCount(); Virtual void print() const; Protected: Int iBase; Static int count; };
不重载基类虚函数的子类:对象中包含子类对象自己的虚表指针,对象类型typeinfo,以及从父类继承下来的成员变量iBase。
子类的虚表【前半部分拷贝的是父类的虚表】,由于没有重载父类虚函数所以无需修改拷贝来的前半部分虚表,【后半部分是子类自己的虚函数们的地址】
Class Derived:public Base{ Public: Derived(int); Virtual ~Derived(); Virtual void derived_print(); Protected: Int iDerived; };
重载父类虚函数的子类:其余与上面一样,不同的是拷贝自父类的虚函数表,由于重载了虚函数,所以相应部分需要修改,指向子类的修改后的虚函数地址。
Class Derived_Overrite:public Base{ Public: Derived_Overrite(int); Virtual ~Derived_Overrite(); Virtual void print()const; Protected: Int iDerived; };
【结论】:
1.父类对象有父类对象的虚函数表,子类对象有子类对象的虚函数表。
2.子类对象的虚表,前半部分拷贝并修改父类的虚表,后半部分是新添加的子类自己的虚函数表。
3.所谓的多态:就是将子类对象赋值给父类指针(因为子类类型亦是父类类型),如此,【父类指针就可以取得子类对象的虚表指针了】,从而访问子类对象重载之后的虚函数。实现基类类型取得派生类重载方法的效果。【当然基类指针取得的子类对象虽然不是阉割的,但是指针的基类类型限制了指针只能访问基类中包含的成员变量和成员函数】
c) 加入多继承,子类的对象构成
i. 其余和单继承的状况一样,不同的是有多个拷贝的基类虚表。对于此的处理如下:基类的虚表按基类的声明顺序来排放;子类新增的虚函数地址放在第一个基类的拷贝虚表后面(不论转成哪种基类类型,子类的虚函数以及子类新增的其他东西,作为父类指针虽然获得了完整的子类对象,但还是访问不到的,所以其实放在哪里都一样)
class Father{ public: virtual void P(){ cout<<"Father\n"; } } ; class Father2{ public: virtual void P2(){ cout<<"Father\n"; } } ; class Son:public Father,public Father2{}; int main(){ Son s; cout<<sizeof(s);//输出结果为8,确实有两个虚表指针 }
【其他测试结论】:上面程序测试表明确实像上图所绘制的一样,包含两个虚表指针,包含多张虚表。有n个基类就有n张虚表。【子类对象的构成就像叠罗汉一样,上面是一个又一个从基类们继承下来的东西,最后才是子类自己新增的东西】。
a) 加入虚继承,子类对象的构成
i. 虚继承是为了解决菱形继承问题。虚继承的子类对象构成和普通继承完全不一样。虚继承的子类对象的子类部分有单独的虚函数表,另外也保存一份父类的虚函数表,两部分之间四字节的0x00000000作为分界。在子类对象的内存中,首先是自己的虚函数表,然后是派生类的成员变量,再后是基类的虚函数表和基类的成员变量
以上参考:http://www.cnblogs.com/skynet/p/3343726.html和《深入探索c++对象模型》