各种调用方式
-
class中有三种function可以调用:static、non-static、virtual,是有差异的。
-
非静态成员函数:Nonstatic Member functions
- C++设计准则是:应该与非成员函数的开销一样。所以其实调用时,会转换为非成员函数的形式,会将object通过this指针的方式传入。成员变量的读取也会转换为this指针的操作。
- 转换之后可能会加上前文提到的NRV优化,以及名称的特殊处理(Name mangling)即重新按照一定的规则命名。
-
虚拟成员函数:
-
静态成员函数
- 它不需要经由 class object才被调用,而是直接调用这个函数,也不需要传入this指针。
虚函数的详细实现
-
单一继承:
- 一个class有一个vtable,里面包含了virtual functions 的地址。包括继承而来的,overrided,以及自己新定义的。每个占用一个格子,从1开始,因为0的位置会放类的信息。
- 这时,如果我要调用z(),那么我不需要知道这个对象是什么。我只需要找到vptr指向的vtbl的slot4位置上的指针即可。
-
多重继承:
- 在多重继承之下,一个 derived class内含n-1个额外的 virtual tables,n表示其上一层 base classes个数(因此,单一继承将不会有额外的 virtual tables)。对于下面这个例子的 Derived 而言(Base1和Base2都有两个同名的虚函数clone,并且二者的析构函数也都是虚函数),会有两个 virtual tables 被编译器产生出来:
- 针对每一个 virtual tables,Derived对象中有对应的vptr,所有会有两个vptr。vptr将在 constructor中被设立初值。
- 在多重继承之下,一个 derived class内含n-1个额外的 virtual tables,n表示其上一层 base classes个数(因此,单一继承将不会有额外的 virtual tables)。对于下面这个例子的 Derived 而言(Base1和Base2都有两个同名的虚函数clone,并且二者的析构函数也都是虚函数),会有两个 virtual tables 被编译器产生出来:
-
虚继承下的v-func:
- 这个草草几句就带过了,总之应该是这样:
- 在derived类的对象模型中,derived和v-base的部分各有一个vptr,但里面都是derived类的vptr的内容。
- 这个草草几句就带过了,总之应该是这样:
inline 函数
- 关键词inline只是一项请求,编译器如果接受,则会将这个函数变成表达式拓展开。
- 编译器首先会评估这个函数的定义,复杂度等。太复杂或者构建问题,编译器则不会把这个变为inline函数。
- 展开:展开时,面对不同情况,编译器可能会做不同的操作。例子是一个min的内联函数:
- 不过inline函数在展开的过程中较为复杂,所以inline需要小心处理。