1)类的大小
class X{};
class Y:virtual public X{};
class Z:virtual public X{};
class A:public Y,public Z{};
大小分别为1 4 4 8
下面计算sizeof(A)
class X的大小(“编译器有无特殊处理”,有特殊处理就是0)
base class y的大小减去“因virtual class X而配置的大小”(4)
base class z的大小减去“因virtual class X而配置的大小”(4)
class A自己的大小(0)
alignment(0)
2)每一个class object必须有足够大小以容纳它所有的非静态数据成员,它可能比你想象的还大,原因
①编译器自动加上了额外的data members,支持如virtual 特性
②alignment的需要
3)member rewriting rule:大意是“一个inline函数实体,在整个class声明未被完全看见之前,是不会被评估求值的”。因此,一个inline member function内部的一个data member绑定操作,会在整个class声明完成之后才发生。
4)data member layout
非静态数据成员在class object中的排序将和其被声明的顺序一样,任何中间介入的static data member都不会被放进对象布局之中。而存放在程序的data segment中。c++ standard要求members的排列只需符合“较晚出现的members在class object中有较高的地址”
5)data member 存取
point3d origin,*pt=&origin;
origin.x=0.0
pt->x=0.0
通过origin存取和通过pt存取,有什么的重大的差异吗?答案是肯定的!
当point3d是一个derived class,而继承结构中有一个virtual base class,并且被存取的member(本例中的x)是一个从该virtual base class 继承而来的member时,就会有重大的差异。这时候我们不能够说pt必然指向哪一种class type(我们不知道编译时期这个member的真正offset),所以这个存取操作会延迟到执行期,经由一个额外的间接引导,才能解决。但如果使用origin,就不会有这些问题,其类型无疑使point3d class ,而即使它继承自virtual base class,member的offset在编译时期也就固定了。
int point3d::*p2=&point3d::x;
point3d::* 的意思是:指向point3d data member的指针类型。所以若取一个static data member的地址,会得到一个指向其数据类型(如int)的指针,而不是一个指向其class member的指针,因为static member并不内含在一个class object之中。
虚拟继承将为“经由base class subobject”存取class members导入一层新的间接性。
比如point3d *pt3d;
pt3d->x=0.0
其执行效率在x是一个struct member、一个class member 、单一继承、多重继承的情况下是完全相同的。但如果x是一个virtual base class的member,存取速度将会稍慢一点。
6)继承与 data member
一般而言,具体继承(相对于虚拟继承而言virtual inheritance)并不会增加空间或时间上的额外负担。
在cfront编译器中,vptr被放置在class object的尾端。这样可以保留base class C struct的对象布局,因而允许在c程序代码中也能使用。
①单一继承而且没有virtual function时的数据布局
②单一继承并且含有虚拟函数情况下的数据布局。
③多重继承
④虚拟继承
parent
|
child
|
grandchild
非虚拟继承:每个父类都有自己的虚表,子类的成员函数被放到了第一个父类的表中。
参见:http://blog.csdn.net/haoel/article/details/1948051
http://blog.csdn.net/haoel/article/details/3081328
http://blog.csdn.net/haoel/article/details/3081385#comments
7)指向 data members的指针
&point3d::z 上述操作将得到z坐标在class object中的偏移位置。最低限度值为x和y的大小总和,因此C++语言要求同一个access level中的member的排序顺序应该和其声明顺序相同。
鉴于取一个nonstatic data member 会得到它在class中的offset,取一个static data member 会得到真正的内存地址。
struct base1{int val1;};
struct base2{int val2;};
struct derived:base1,base2{};
printf("&base1::val1:%p \n",&base1::val1);
printf("&base2::val2:%p \n",&base2::val2);
printf("&derived::val1:%p \n",&derived::val1);
printf("&derived::val2:%p \n",&derived::val2);
结果全为0
class X{};
class Y:virtual public X{};
class Z:virtual public X{};
class A:public Y,public Z{};
大小分别为1 4 4 8
下面计算sizeof(A)
class X的大小(“编译器有无特殊处理”,有特殊处理就是0)
base class y的大小减去“因virtual class X而配置的大小”(4)
base class z的大小减去“因virtual class X而配置的大小”(4)
class A自己的大小(0)
alignment(0)
2)每一个class object必须有足够大小以容纳它所有的非静态数据成员,它可能比你想象的还大,原因
①编译器自动加上了额外的data members,支持如virtual 特性
②alignment的需要
3)member rewriting rule:大意是“一个inline函数实体,在整个class声明未被完全看见之前,是不会被评估求值的”。因此,一个inline member function内部的一个data member绑定操作,会在整个class声明完成之后才发生。
4)data member layout
非静态数据成员在class object中的排序将和其被声明的顺序一样,任何中间介入的static data member都不会被放进对象布局之中。而存放在程序的data segment中。c++ standard要求members的排列只需符合“较晚出现的members在class object中有较高的地址”
5)data member 存取
point3d origin,*pt=&origin;
origin.x=0.0
pt->x=0.0
通过origin存取和通过pt存取,有什么的重大的差异吗?答案是肯定的!
当point3d是一个derived class,而继承结构中有一个virtual base class,并且被存取的member(本例中的x)是一个从该virtual base class 继承而来的member时,就会有重大的差异。这时候我们不能够说pt必然指向哪一种class type(我们不知道编译时期这个member的真正offset),所以这个存取操作会延迟到执行期,经由一个额外的间接引导,才能解决。但如果使用origin,就不会有这些问题,其类型无疑使point3d class ,而即使它继承自virtual base class,member的offset在编译时期也就固定了。
int point3d::*p2=&point3d::x;
point3d::* 的意思是:指向point3d data member的指针类型。所以若取一个static data member的地址,会得到一个指向其数据类型(如int)的指针,而不是一个指向其class member的指针,因为static member并不内含在一个class object之中。
虚拟继承将为“经由base class subobject”存取class members导入一层新的间接性。
比如point3d *pt3d;
pt3d->x=0.0
其执行效率在x是一个struct member、一个class member 、单一继承、多重继承的情况下是完全相同的。但如果x是一个virtual base class的member,存取速度将会稍慢一点。
6)继承与 data member
一般而言,具体继承(相对于虚拟继承而言virtual inheritance)并不会增加空间或时间上的额外负担。
在cfront编译器中,vptr被放置在class object的尾端。这样可以保留base class C struct的对象布局,因而允许在c程序代码中也能使用。
①单一继承而且没有virtual function时的数据布局
②单一继承并且含有虚拟函数情况下的数据布局。
③多重继承
④虚拟继承
parent
|
child
|
grandchild
非虚拟继承:每个父类都有自己的虚表,子类的成员函数被放到了第一个父类的表中。
参见:http://blog.csdn.net/haoel/article/details/1948051
http://blog.csdn.net/haoel/article/details/3081328
http://blog.csdn.net/haoel/article/details/3081385#comments
7)指向 data members的指针
&point3d::z 上述操作将得到z坐标在class object中的偏移位置。最低限度值为x和y的大小总和,因此C++语言要求同一个access level中的member的排序顺序应该和其声明顺序相同。
鉴于取一个nonstatic data member 会得到它在class中的offset,取一个static data member 会得到真正的内存地址。
struct base1{int val1;};
struct base2{int val2;};
struct derived:base1,base2{};
printf("&base1::val1:%p \n",&base1::val1);
printf("&base2::val2:%p \n",&base2::val2);
printf("&derived::val1:%p \n",&derived::val1);
printf("&derived::val2:%p \n",&derived::val2);
结果全为0
为什么第四个返回的也是0呢,很可能编译器已经内部处理过了。