C++对象模型
C++中数据成员有两种:static和nonstatic,以及三种classmember functions:static nonstatic和virtual
现在标准C++对象模型:
Nonstatic data Members被置于每一个classobject之内,static data members则被存放在所有的class object之外,static和nonstatic function members也被放在所有的class object之外,virtual functions则以两个步骤支持:
每一个class产生出一堆指向virtualfunctions的指针,放在表格之中,这个表格被称为virtual table(vtbl)
每一个classobject被添加一个指针,指向相关的virtual table,通常这个指针被称为vptr,vptr的设定和重置都由每一个class的constructor、destructor和copy assignment运算符自动完成,每一个class所关联的type_info object(用以支持runtime type identification,RTTI)也经由virtual table 被指出来,通常放在表格的第一个slot处。
C++中可以支持单重继承、多重继承、虚拟继承,在虚拟继承的情况下,base class不管在继承串链中被派生多少次,永远只会存在一个实体。
虽然你可以直接或间接处理继承体系中的一个base class object,但只有通过pointer或reference的间接处理,才支持OO程序设计所需的多态性质。这句话的意思是可以通过指针或引用来完成多态的目的。
也就是说,只有通过引用或指针才可能实现virtual机制。
那么需要多少内存才能表现一个class object?
其nonstatic members的总和大小:
加上任何犹豫alignment(对齐)的需求而填补(padding)上去的空间(可能存在于members之间,也可能存在于集合体边界)
加上为了支持virtual 而由内部产生的任何额外负担。
对于指针类型的理解:
同时需要说明一点,一个指针(或一个引用),不管它指向哪一种数据类型,指针本身所需的内存大小是固定的。所以对于任何类型的指针或引用,它所占用的空间大小是固定的。
既然一个指针无论指向哪一种类型,他们的内存大小是固定的,那么如何判断指向不同类型的指针时不同的呢?比如一个指向整数的指针或一个指向对象的指针有所不同呢?
从内存需求观点来说,没有什么不同!他们三个都需要有足够的内存来放置一个机器地址。“指向不同类型之各指针”间的差异,既不在其指针表示法不同,也不再其内容(代表一个地址)不同,而是在其所寻址出来的object类型不同,也就是说,“指针类型”会教导编译器如何解释某个特定地址中的内存内容及其大小。也就是说,编译器知道某个指针所指向的空间的大小。比如一个指向整形的指针所指向的空间大小就是4个字节。指向一个对象的指针所指向的空间的大小就是这个对象的大小。
那么问题又来了,一个指向地址1000而类型为void*的指针,将涵盖怎样的地址空间呢?我们不知道,这就是为什么一个类型为void*的指针只能够含有一个地址,而不能够通过它操作所指之object的缘故。所以,转型其实是一种编译器指令,大部分情况下它并不改变一个指针所含的真正地址,它只影响“被指出之内存的大小和其内容”的解释方式。
如果在多态的情况下使用指针呢?
来看看在多态情况下指针的作用,假如有一个基类ZooAnimal,一个子类Bear,那么
Bear b;
ZooAnimal* pz =&b;
Bear* pb=&b;
这么一来,pz pb的大小都是一定的,假设b存储的地址是1000,那么这两个指针有什么不同呢?它们每个都指向Bear object的第一个byte,差别是,pb所涵盖的地址包含真个Bear object,而pz所涵盖的地址只包含Bear object中的ZooAnimal subobject.
除了ZooAnimal subobject中出现的members,你不能够实用pz来直接处理Bear的任何members,唯一的例外是通过virtual机制。如果有了virtual机制,在执行的时候会在vptr尽心相关的type_info查看。
一个pointer或一个reference值所以支持多态,是因为他们并不引发内存中任何“与类型有关的内存委托操作”,会受到改变的只是他们所指向的内存的“大小和内容解释方式”而已。也就是说,指向不同类型的指针,其在编译期间会决定这个指针所指向的内存的大小和内容的解释方法。比如指向int的指针,在编译的时候已经确定,这个指针指向的内存大小为4字节内容是一个int。比如指向struct的指针,在编译的时候已经确定,这个指针指向的内存大小为sizeof(struct),指向的内容是这个struct中的内容。对于指针参与到virtual机制时,是另外的一个考虑。