一、Data Member的存取
static data members,会被编译器提出于class之外,并被视为一个global变量(但只在class生命范围之内可见)。每一个member的存取许可(private, protected, public),以及与class的关联,并不会导致任何空间上或执行时间上的额外负担——不论是在个别的class objects或是在static data member本身。每一个static data member只有一个实体,存放在程序的data segment之中。
nonstatic data members直接存放在每一个class object之中。每一个nonstatic data member的偏移量(offset)在编译时期即可获知,甚至如果member属于一个base class subobject(派生自单一或多重继承串链)也是一样。因此,存取一个nonstatic data member,其效率和存取一个C struct member或一个nonderived class的member是一样的。
但是使用继承和指针还是会带一些差异的,如下代码:
// Point3d是一个derived class 其定义就忽略哈 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,members的offset位置也在编译时期就固定了。
二、”继承“与Data Member
在继承体系中,关于derived class members和base class(es) members的内存布局中的排列次序并未在C++ Standard中强制指定;理论上编译器可以自由安排之。在大部分编译器上头,base class members总是先出现,但属于virtual base class除外(一般而言,任何一条规则一旦遇上virtual base class基本就难成立的了)。
下面将分别讨论“单一继承且不含virtual function”、“单一继承并含virtual functions”、“多重继承”、“虚拟继承”等四种情况的继承模型。
1.单一继承且不含多态

单一继承而且没有多态时的数据布局
这里有一个易犯了的错误,把一个class分解为两层或更多层,有可能会为了“表现class体系之抽象化”而膨胀所需的空间。例子如下:
class Concrete {
public:
//...
private:
int val;
char c1;
char c2;
char c3;
};
在一部32位机器中,每一个Concrete class object的大小都是8 bytes,细分为(1)val占用4 bytes;(2)c1,c2,c3各占用1 bytes;(3)alignment需要1 byte。如下图所示:

假如将上述的Concrete分裂为三层的继承结构表示的话:
class Concrete1 {
public:
//...
private:
int val;
char c1;
};
class Concrete2 : public Concrete1 {
public:
//...
private:
char c2;
};
class Concrete3 : public Concrete2 {
public:
//...
private:
char c3;
};
经过这样分裂的设计后,Concrete3 object的大小不再是8 bytes了,而是16 bytes了。其继承结构的内存布局如下:

之所以出现这种情况是因为C++语言保证”出现在derived class中的base class subobject有其完整性原样性”,正是如此,继承后的Concrete3 object会因为继承串链中的父类alignment的空间而导致本身的空间膨胀.
2.加上多态
加上多态后,不可避免地在数据结构中多了一个vptr,C++ Standard没有规定vptr放在对象结构的位置。把vptr放在class object的尾端,可以保留base class C struct的对象布局,因而允许在C程序代码中也能使用。把vptr放在前端,对于“在多重继承之下,通过指向class members的指针调用virtual function”,会带来一些帮助,而代价就是丧失了C语言兼容性。
3.多重继承
相对于加入多态的单一继承,多重继承在把一个derived object转换为其base类型时,需要由编译器的介入,用以调整地址。具体来说,对于一个多重继承对象,将其地址指定给“最左端(也就是第一个)base class的指针”,情况将和单一继承时相同,因为二者都指向相同的起始地址。需付出的成本只有地址的指定操作而已。至于指定给第二个或后继的base class的地址指定操作,则需要将地址修改过:加上(或减去,如果downcast的话)介于中间的base class subobject(s)大小。
4.虚拟继承
多重继承的一个语意上的副作用就是,它必须支持某种形式的”shared subobject”继承。一个典型的例子是最早的iostream library:
class ios { ... };
class istream : public ios { ... };
class ostream : public ios { ... };
class iostream : public istream, public ostream { ... };
这样在iostream中得维护两份ios的subobject,而解决这个问题是使用虚拟继承:
class ios { ... };
class istream : public virtual ios { ... };
class ostream : public virtual ios { ... };
class iostream : public istream, public ostream { ... };
至于虚拟继承的一般实现方法如下所述。Class如果内含一个或多个virtual base class subobjects,像istream那样,将被分割成两部分:一个不变局部和一个共享局部。不变局部中的数据(实际上是在本类而非在base class中定义的data members),不管后继如何衍化,总是拥有固定的offset(从object的开头算起),所以这一部分数据可以被直接存取。至于共享局部,所表现的就是virtual base class subobject。这一部分的数据,其位置会因为每次的派生操作而会有所变化,所以它们只可以被间接存储(如在istream中的ios)。一般的布局策略是先安排好derived class的不变部分,然后再建立其共享部分。
有两个实现模型,第一个是在每个类中添加一个指针,用于指向共享局部的地址,即使共享局部在后继的继承中出现布局变化,但指针仍然会在编译阶段设定为正确的地址。另一个模型则是通过在virtual table上放置offset(相对于对象开头)来获取共享局部的地址。