各种调用方式
- {P140} C++支持三种类型的member functions: static, non-static和virtual。
non-static member function
- {P141} C++的设计准则之一便是: non-static member function至少必须和一般的non-member function有着相同的效率。转换步骤为:
- 改写原型(签名), 添加一个this指针作为第一个参数。同理,如有const修饰符,相当于加在这个this上。
- 用this指针修改所有存取的地方。
- 作为一个外部函数,具有mangled过的名字
virtual function
- {P147} 如果一个虚函数里面调用了另外一个虚函数,那么另一个虚函数无需使用虚函数表进行调用,因为已经决议到该虚函数了,所以已经确定了,可以直接调用该类有的,提高效率。
static function
- {P151} 不可以直接存取non-static数据,不可以是const, volatile, virtual。
- static函数可以作为callback 运用到thread上。
各种情况下的 virtual function
- 单一继承很简单,virtual table pointer找到virtual table,按照对应的offset得到function point. eg:
(*ptr->vptr[offset])(ptr)
- {P159} 多重继承,其复杂度围绕在第二个及后继的base身上,以及“必须在执行期调整this指针”。有两种解决思路:
- {P161} 把virtual table的entry变成address+offset,但缺点是空间浪费,因为这样不是多重继承的虚函数表项也需要两个域。eg:
(*ptr->vptr[off].faddr)(ptr+ptr->vptr[off].offset)
- {P162} thunk。所谓thunk是一小段assembly代码,用来 1) 以适当的offset值来调整this指针 2) 并跳到相应的virtual function。thunk技术允许virtual table slot继续内含一个简单的指针,不需要任何空间上的额外负担。虚表项中地址可以直接指向virtual function,也可以指向一个相关的thunk。eg:
Base2 *ptr = new Derived;
ptr必须向后调整sizeof(Base1)
调用对应的~D时,需要将ptr调整回到Derived.
Derived *pder = new Derived;
pder->mumble();
需要调整pder sizeof(Base1)
- {P169} 虚拟继承,不建议在virtual base中声明non-static data。
指向member function的指针
- {P176} 对一个nonstatic member function取址,得到的是该函数在内存中的地址;而面对一个virtual function,得到的将是一个索引值。必须被绑定于一个class object上,才能够通过它调用函数。
class Point {
public:
virtual ~Point();
float x();
float y();
virtual float z();
}
取dtor, &Point::~Point 得到的结果是1;
取&Point::x和&Point::y则为地址;
取&Point::z是数值2;
float (Point::*pmf)() = &Point::z;
Point *ptr = new Point3d;
(*ptr->vptr[(int)pmf]) (ptr);