本章由下面问题引出:
当存在如下代码:
float 
Point3d::magnitude() const 
{ 
   return sqrt( 
         _x * _x + _y * _y + _z * _z 
   ); 
} 
 
Point3d Point3d::normalize() const 
{ 
   register float mag = magnitude(); 
   Point3d normal; 
 
   normal._x = _x/mag; 
   normal._y = _y/mag; 
   normal._z = _z/mag; 
 
   return normal; 
} 
 
Point3d obj; 
Point3d *ptr = &obj; 
 
进行这样函数调用:
obj.normalize();
ptr->normalize();
会发生什么事?
 
答案是:不确定。因为C++支持三种类型的成员函数:nostaticstaticvirtual,每种类型的函数的被调用的方式不同!
 

4.1 Member的各种调用方式

1)非静态成员函数
C++设计准则之一:非静态成员函数至少必须和一般的非成员函数有相同的效率。
 
方法是:编译器内部已将“成员函数实体”转换为“非成员函数实体”
 
转换步骤:
1.       改写函数的signature(函数原型),即安插一个额外形参,该参数为this指针。对于非静态非const的成员函数,安插的this指针是const的,即是X *const thisX为一个类;对于对于非静态const的成员函数,安插的this指针是const且所指对象也是const的,即const X *const this。这也是“const对象、指向const对象的指针或引用只能用于调用其const成员函数,如果尝试用它们调用非const成员函数,则是错误的(C++ Primer 4th 7.7.1)”的原因。
2.       将函数体中“对nonstatic data member”的存取操作改为经由this指针来存取。
3.       member function重新写成一个外部函数,对函数名进行处理,使它在程序中成为独一无二的名称。
经过上述处理,normalize函数变成类似下面的外部函数(假设Point3d copy constructor已声明,NRV优化已实施)
extern void normalize__7Point3dFv(
   register const Point3d *const this,
Point3d &__result ) /*多一个__result参数的原因P63——P71*/
{
   register float mag = this->magnitude();
 
   // default constructor
   __result.Point3d::Point3d();
 
   __result._x = this->_x/mag;
   __result._y = this->_y/mag;
   __result._z = this->_z/mag;
 
   return;
}
对该函数调用的操作也需要修改, 于是
obj.normalize();
变成:
Point3d res;
normalize__7Point3dFv(&obj, res);
ptr->normalize();
变成:
Point3d res;
normalize__7Point3dFv(ptr, res);
 
若未进行NRV优化,则
obj.normalize();
变成:
normalize__7Point3dFv(&obj);
ptr->normalize();
变成:
normalize__7Point3dFv(ptr);
 
名称处理:
待整理
 
2)虚成员函数
normalize()是一个虚函数,则以下调用:
ptr->normalize();
则转化成:
( * ptr->vptr[ 1 ])( ptr );
其中:
l         vptr是编译器产生的指针,指向虚表(virtual table),每个包含一个或多个虚函数的类对象都会包含一个vptr
l         1virtual table slot的索引值,它关联normalize()函数
l         ( ptr )中的(ptr 表示this指针
 
而对于以下调用
// Point3d obj;
obj.normalize();
则没有必要转化成
*obj.vptr[1])(&obj
而应该转化成这样:
normalize__7Point3dFv(&obj); /*即和非静态成员函数调用一样*/
因为经由一个类对象或类域操作符(::)调用一个虚函数,这种操作总是像调用一般非静态成员函数一样。(只有通过引用或指针,虚函数才可能呈现多态性)
3)静态成员函数
normalize()是一个静态成员函数,则以下调用:
obj.normalize();
ptr->normalize();
则转化成:
// obj.normalize();
normalize__7Point3dSFv();
// ptr->normalize();
normalize__7Point3dSFv();
 
静态成员函数的主要特性是没有this指针,下面的次要特性都根源于此主要特性
1.       不能直接存取类中的非静态成员
2.       不能被声明为constvolatilevirtual
3.       不需要(但可以)经由类对象才被调用,通常使用类::调用静态成员函数
 
若取一个静态成员函数的地址,则就是其在内存中的地址,其地址的类型并不是一个“指向类成员函数的指针”,而是一个“非成员函数指针”。
例如,对于静态成员函数
unsigned int 
Point3d:: object_count() 
{ 
   return _object_count; 
} 
会转换成:
unsigned int
object_count__5Point3dSFv()
{
   return _object_count__5Point3d;
}
&Point3d::object_count(); 
会得到一个数值,其类型是:
unsigned int (*)();
而不是
unsigned int ( Point3d::* )();
 
静态成员函数由于缺乏this指针,因此差不多等同于非成员函数。