1.多态的作用是什么?
多态的主要用途是经由一个共同的接口来影响类型的封装。这个接口一般定义在一个抽象的class object当中,由virtual function 机制引发,它可以在执行期间根据object的真正类型解析出到底使用的是哪一个函数实体。
2.哪些方式支持多态?
- 经由一组隐含的转化操作。例如将一个derived class指针转化为一个base class指针。
- 经由virtual function机制
- 经由dynamic_cast和typeid的运算符
3.一个class object多少内存?
- 所有nonstatic data member的大小
- 由于alignment字节对齐所补上去的空间
- 为了支持virtual内部产生的额外负担,如vptr
4.产生nontrivial default constructor的四种情况
- 带有“default constructor"的member class object
- 带有”default constructor"的base class
- 带有一个”virtual function"的class
- 带有一个”virtual base class"的class
5.不展现bitwise copy 语义,合成copy constructor的四种情况
- 带有“copy constructor"的member class object
- 带有”copy constructor"的base class
- 带有一个”virtual function"的class,这种情况会增加一个virtual function table ,并重新设定vptr
- 带有一个”virtual base class"的class,这种情况会设定virtual base class pointer/offset的初值
6.class constructor的初始化次序:
- 首先判断如果有virtual base class,有多个则按照从左到右,从深到浅的次序初始化
- 使用member initialization list 初始化virtual base class,如果有参数需要传递则必须传递
- 不在list中,但virtual base class有default constructor,则使用default constructor初始化
- class中每一个virtual base class subobject 的偏移量offset,必须在执行期可被存取
- 然后判断如果有nonvirtual base class,有多个则按照base class的声明次序初始化
- 使用member initialization list 初始化base class,如果有参数需要传递则必须传递
- 不在list中,但base class有default constructor,则使用default constructor初始化
- 当初始化第二个及后继的base class时,this指针需要调整
- 初始化每一个vptr,将其指向适当的virtual function table
- 初始化member成员变量,有多个则按照member声明次序初始
- 使用member initialization list 初始化member,与list的顺序无关,还是按照member声明次序初始化
- 不在list中,但member有default constructor,则使用default constructor初始化
7.什么时候必须使用member initialization list初始化?
- 当初始化一个reference member
- 当初始化一个const member
- 当有一个base class,并且它由一组参数
- 当有一个virtual base class,并且它有一组参数
8.空类的sizeof多少?
sizeof的大小是1 byte
那是编译器按插进去的一个char,可以使这个class的两个实体在内存中得以分配独一无二的地址
9.data member的存取?
- static data member
- 位置:放在class之外,存放在data segment当中
- 实体:只有唯一一个实体
- 存取:不由this指针存取
- 取地址:会得到一个指向其类型数据的指针,而不是一个指向class member的指针
- nonstatic data member
- 位置:存放在class之中
- 存取:由this存取,并且编译器需要把class object的起始地址,加上class member的偏移量offset(=&Point::x-1)
- 取地址:得到一个指向class data member的指针,其offset值总是被加上1
10.继承中的data member 的内存模型
- 单一继承,不含virtual functions
float x |
float y |
float x |
float y |
float z |
- 单一继承,含有virtual functions
float x |
float y |
__vptr_A |
float x |
float y |
__vptr__A |
float z |
- 多重继承
float x |
float y |
__vptr_A |
float x |
float y |
__vptr__A |
float z |
C *next |
__vptr_C |
float x |
float y |
__vptr__A |
float z |
C *next |
__vptr_C |
float q |
注意:对于一个多重继承对象,将其地址指向给第一个base class的指针,其情况和单一继承一样,具有相同的起始地址
但将其地址指向给第二个base class及后继类型的指针,其地址需要修改
- 虚拟继承
float x |
float y |
__vptr__A |
float z |
A *ptrA |
__vptr__B |
float x |
float y |
__vptr__A |
C *next |
A *ptrA |
__vptr__C |
float x |
float y |
__vptr__A |
float z |
A *ptrA |
__vptr__B |
C *next |
A *ptrA |
__vptr__C |
float more |
float x |
float y |
__vptr__A |
注意:virtual base class offset偏移量存放在virtual function table中,以负值索引存取
11.member functions 的调用方式
- nonstatic member functions
- 内化为static member function:
- 安插一个额外this指针
- 对每一个nonstatic data member的存取操作均由this指针存取
- member function 重写为一个外部函数(mangling)
- virtual member functions:会通过vptr调用virtual table中根据索引值取对应的虚函数,函数参数含this指针
- static member functions
12.active virtual function
- (激活一:)继承自base class的函数实体,即derived class 决定不override的情况下
- (激活二:)这个class自己定义的函数实体,即derived class 决定override的情况下
- (激活三:)pure_virtual_called()函数实体,既可以当纯虚数,也可以当作执行器异常处理函数
13.对于virtual function的调用,在编译时期可知:
- 我们不知道ptr所指的对象的真实类型,但是我们知道通过ptr能够存取对象的virtual table
- 我们不知道哪个类型的函数实体x()被调用,但是我们知道每一个x()函数地址都会放在slot索引值为n的槽中
14. virtual function的内存模型
- 单一继承
- (激活一:)base class的函数实体地址拷贝到derived class的virtual table相对应的slot当中
- (激活二:)overriding的函数实体地址必须放置对应的slot当中
- 自己加入一个新的virtual function,此时virtual table增大一个slot,新的函数实体地址会存放在这个slot当中
- 多重继承:
- 对于多重继承,一个derived class会产生n-1个额外的virtual table(n为base class的数量),分为:
- 主要表格,与base1共享
- 次要表格,与base2有关
- 必要的this指针调整
- 当一个base2 class的指针指向一个derived class的对象时,被处理的是次要表格(base2 class类),由于调用的是derived class的virtual function,在调用之前this指针指向的是base2 subobject的位置,先要将指针调整至derived对象的起始处
- 当一个derived class的指针指向一个derived class的对象时,被处理的是主要表格(derived class类),由于调用继承自base2 class的virtual function,在调用之前this指针指向的是derived对象的起始处,先要将指针调整至base2 subobject的位置
- 对于多重继承,一个derived class会产生n-1个额外的virtual table(n为base class的数量),分为:
- 虚拟继承
- 对于继承体系中的virtual base class,每一个derived class都有一个virtual table存放了virtual base class subobject距离derived对象起始处的偏移值offset,并且将它存放在virtual table中以负数为索引的slot中