CPP Object Model: Function Member
目录

三种member functions:

  • non-static
  • virtual
  • static

member functions三种特性:

  • const
  • volatile
  • virtual

non-static member function

non-static member function:

class A {
A func();            // non-const nonstatic member
A func() const;      // const nonstatic member
};

func(const A* a);        // nonmember function

对于这些函数的调用,1. 首先改写函数signature以安插一个额外参数:

A A::func(A* const _this);            // non-const nonstatic member
A A::func(const A* const _this);      // const nonstatic member

然后2. 对每一个nonstatic data member的存取改为由_this指针来存取。 最后3. 进行name mangling使函数名在程序中唯一(data member也需要):

void _ZN1A4funcEv(A* const _this, A *__result);              // G++, NRV
void _ZNK1A4funcEv(const A* const _this, A *__result);

name mangling并没有统一的标准,大体由以下部分组成:

  • 类名:不同class可能有同名函数
  • 函数名
  • 参数类型列表: 支持重载

由上,对于non-static member function的调用,直接转化成对函数的调用,没有多余的代价:

A a;
A* pa = &a;

a.func();      // => _ZN1A4funcEv(&a);
pa->func();    // => _ZN1A4funcEv(pa)

virtual member functions

virtual memeber functions需要查找vtbl来调用(resolved决议)。 每种class的vtbl内容是固定。 object的动态类型决定了它的vptr指向的vtbl。 derived class vtbl构造时(只一次)会把base class vtbl复制一份,并重新关联dervied class重写的vfunc。 也就是说,对于derived class的vtbl,如果derived class重写了vfunc,并不会改变这个vfunc在base class vtbl中的solt位置, 只会在derived class vtbl中重新把这个solt关联到derived class的vfunc。 如果derived class新添加了vfunc,则在derived class vtbl末尾新添加一个solt,关联到这个新的vfunc(P155)。

因此目标vfunc是vtbl中第几个solt关联的函数在编译时就可以确定, 因为通过静态类型就可以知道这个object关联了哪些vfunc,目标vfunc位于vtbl第几个solt。 通过动态类型(运行时在生成object时重新设定了vptr)vptr获得object真正的vtbl,从而访问和静态类型相同位置的solt,找到真正关联的vfunc。

多重继承情况下,derived class object有多个vptr分别指向vtbls,vtbl个数和基类个数相等(vtbl并不是base class的vtbl)。 因此一个class可能有多个vtbl。 object根据静态类型决定使用哪一个vtbl。(P165)

虚拟继承情况下,virtual base class object的偏移也在vtbl中,其solt位置在编译时期也可以知道。

因此,虚函数的访问在编译时就可以知道solt在vtbl中的位置,在运行时才能获得真正关联的函数。 虚函数的代价就是随机访问vtbl的时间。

static member functions

不通过object就可以调用static member functions。

发表评论