Nonstatic Member Function 的语意
C++ 的设计准则之一就是: nonstatic member function 至少必须和一般的 nonmember function 有相同的效率。 这就是说, 如果我们在以下两个函数之间做选择:
float magnitude3d(const Point3d *_this){...} float Point3d::magnitude3d() const {...}
那么选择 member function 不因该有什么额外负担, 这是因为编译器内部已将 member 函数实体转换为对等的 nonmember 函数实体。
举个例子, 下面是 magnitude() 的一个 nonmember 定义:
float magnitude3d(const Point3d *_this) { return sqrt(_this->_x *this->_x + _this->_y *this->_y + _this->_z *this->_z); }
乍看之下似乎 nonmember function 比较没有效率, 它间接地经由参数取用坐标成员, 而 member function 却是直接取用坐标成员。 但是实际上 member function 被内化为 nonmember 的形式。以下是转换步骤:
1. 改写函数的 signature 以安插一个额外的参数到 member fucntino 中,用以提供一个存取管道, 使 class object 得以调用该函数。该额外函数被称为 this 指针:
//non-const nonstatic member 的增长过程 Point3d Point3d::magnitude(Point3d *const this) //如果 memberfunction 是 const, 则变成: //const nonstatic member 的扩张过程 Point3d Point3d::magnitude(const Point3d *const this)
2. 将每一个对 nonstatic data member 的存取操作改为经由 this 指针来存取:
{ return sqrt(_this->_x *this->_x + _this->_y *this->_y + _this->_z *this->_z); }
3. 将 member fucntion 重现写成一个外部函数, 对函数名称进行 mangling 处理, 使它成为程序中独一无二的语汇:
extern magnitude__7Point3dFv( register Point3d *const this);
转换好了之后其每个调用操作也需要转换, 于是:
//你看到的 obj.magnitude(); //转换为 mgnitude__7Point3dFv( &obj ); //你看到的 ptr->magnitude(); //变成了: magnitude__7Point3dFv(ptr); //你看到的 Point3d Point3d::normalize() const { register float mag = magnitude(); Point3d normal; normal._x = _x / mag; normal._y = _y / mag; normal._z = _z / mag; return normal; } //内部转化为 void normalize__7Point3dFv(register const Point3d *const this, Point3d &__result) { register float mag = this->magnitude(); //default constructor __result._x = this->_x / mag; __result._y = this->_y / mag; __result._z = this->_z / mag; return; } //另一个比较有效率的方法 Point Point3d::normalize() const { register float mag = magnitude(); return Point3d( _x/mag, _y / mag, _z / mag); } //这个方法会被转化为 void normalize__7Point3dFv( register const Point *const this, Point3d &__result) { register float mag = this->magnitude(); __result .Point3d::Point3d( _x/mag, _y / mag, _z / mag ); return; }
这可以节省 default constrctor 初始化所引起的负担。