首页 > 代码库 > C++之类的成员函数的调用 vs. 普通函数的调用
C++之类的成员函数的调用 vs. 普通函数的调用
首先请看下面的语句:
Point3d obj; Point3d *ptr = &obj;
当使用上述指针或者对象调用成员函数Func()时,会有:
obj.Func(); ptr->Func();
上述调用的背后到底完成了一些什么呢?
假设Func函数的定义如下:
Point3d Point3d::Func() const { Float a = getA(); Point3d ret; ret._x = _x/a; ret._y = _y/a; ret._z = _z/a; return ret; }
getA的定义为:
float Point3d::getA() { return sqrt(_x*_x+_y*_y+_z*_z); }
那么看过这些函数的定义之后,我们能否得知上述代码的执行过程呢?答案是不行!上述的代码最多能告诉我们Func函数一定不是static。(因为它操作了non-static成员变量,以及是const函数)。
那么上面这样的成员函数的调用过程到底是怎么完成的呢?
C++的设计准则之一是:non-static成员函数的调用与非成员函数的调用的效率应该是一致的。选择将函数声明为成员函数是不应
该有任何的额外负担的。于是乎编译器在调用成员函数的时候是将其视为非成员函数来调用的。
例如:一个getA的非成员函数的定义为:
float getA(const Point3d *this) { return sqrt(this->_x* this->_x + this->_y * this->_y + this->_z * this->_z); }
这样的函数会给我们一个错觉,那就是非成员函数的调用是效率较低的,因为它是间接地去得到对象的各个成员变量的。而在成员函数里面我们是直接使用的。其实这是一个很大的误区。
这里其实可以很简单的理解一下,类的成员函数其实是有一个隐含的形式参数的,那就是this指针。然而编译器就是这么做的,编译器按照下面的步骤来处理成员函数的调用的:
1 改写成员函数的函数原型,将那个隐含的this指针表示出来。提供一个存取的管道,也就是说我们的函数中调用的就是这个形参(this)的成员变量。如下:
Point3d Point3d::Func ( Point3d * const this)
注意此处const的位置,this指针本身是const的。如果该成员函数本身也是一个const成员函数的话,那么该函数原型应该是
Point3d Point3d::Func ( const Point3d * const this)
2 将该函数中的成员变量使用this指针来进行间接存取。例如:
{
return sqrt(this->_x* this->_x + this->_y * this->_y + this->_z * this->_z);
}
3 将成员函数重新书写为一个外部函数,但是这里值得注意的一个技术“mangling”这个是C++里用于处理重载的同名函数的一个技术。使得该函数名字在程序中是独一无二的。
上述的Func函数或许会处理为下面的名字:(不同的编译器处理方式不同)
Extern Func_Point3dFv(Point3d *const this);
OK!大功告成,现在上面的 obj.Func()的调用就变成了 Func_Point3dFv(&obj)。
这里的整个过程都是编译器在诉说 “成员函数的调用的效率必须与非成员函数一致”。
[updated] 使用类作用域符号调用成员函数(无论是虚函数还是非虚函数),编译器的决议方式与non-static成员函数是一致的。
使用对象调用成员函数(无论是虚函数还是非虚函数),编译器的决议方式与non-static成员函数是一致的。
C++之类的成员函数的调用 vs. 普通函数的调用