【一文读懂】C++成员函数的调用方式

【一文读懂】C++成员函数的调用方式

引言

在C++中,有三种成员函数,按照加入C++的先后顺序排列如下:

nonstatic member functions

virtual member functions

static member functions

经过编译器的处理之后,这三种成员函数的调用方式是不相同的,下边我们一个一个看。

我们提供这样一个类Point3d,作例子:

1

2

3

4

5

6

7

8

9

10

11

12

class Point3d {

public:

float magnitude() const;

private:

float _x;

float _y;

float _z;

}

float Point3d::magnitude() const{

return sqrt(_x * _x + _y * _y + _z * _z);

}

Nonstatic Member Functions

C++有这样一个设计准则:非静态成员函数至少要和一般的非成员函数有相同的效率。也就是说,如下两个函数:

1

2

float magnitude3d(const Point3d* _this){...} //非成员函数

float Point3d::magnitude3d() const {...} //成员函数

选择第二个函数不应该给程序带来性能上的损失,否则我还不如直接选第一个函数(不让它做类的成员函数)。

那编译器是怎么保证这个原则的呢?答案是编译器内部会把成员函数转换为对等的非成员函数。

举个例子,下面是magnitude()的非成员函数版定义:

1

2

3

4

5

float magnitude(const Point3d* _this){

return sqrt(_this->_x * _this->_x +

_this->_y * _this->_y +

_this->_z * _this->_z);

}

乍一看,成员函数版应该效率更高,因为它直接取用_x,_y,_z这三个成员,而非成员函数版要通过指针间接取用。其实不然,因为成员函数版会被编译器内化为非成员函数版,转化步骤如下;

改写函数原型,安插一个额外的参数(this指针)到成员函数。

非const的非静态成员函数改写如下:

1

Point3d::magnitude(Point3d *const this)

即添加了一个指针常量this。

const的非静态成员函数改写如下:

1

Point3d::magnitude(const Point3d* const this)

即添加一个指向常量的指针常量this。

把每一个对非静态数据成员的存取操作改成通过this指针来存取:

1

2

3

4

5

6

7

{

return sqrt(

this->_x * this->_x +

this->_y * this->_y +

this->_z * this->_z

);

}

将成员函数重新写成一个外部函数。将函数名称通过“mangling”,使它称为程序中独一无二的词汇:

1

extern magnitude__7Point3dFv(register Point3d* const this);

经此三步,这个函数的转换就完成了。之后,每个调用操作也会被转换。比如:

1

2

3

4

Point3d obj;

Point3d* ptr = &obj;

obj.magnitude();

ptr->magnitude();

以上两个调用操作,就会被分别转换为:

1

2

magnitude__7Point3dFv(&obj);

magnitude__7Point3dFv(ptr);

Virtual Functions

如果magnitude()是一个虚函数,那么以下调用:

1

ptr->magnitude()

就会被内部转化为:

1

(* ptr->vptr[1])(ptr);

整体其实是通过函数指针调用magnitude()函数;

vptr是编译器产生的指针,指向虚表;

1是虚表slot的索引值,关联到magnitude()函数;

第二个ptr表示this指针。

Static Member Functions

静态成员函数的主要特性是它没有this指针。因为它没有this指针,所以静态成员函数有以下特点:

它不能直接操作类中的非静态成员;

它不能是const、volatile或virtual的;

它不需要经过类的对象来调用(尽管很多时候我们仍是这样调用它)。

如果magnitude()是一个静态成员函数,那么以下调用:

1

2

obj.magnitude();

ptr->magnitude();

会被转换为一般的非成员函数调用,像这样:

1

magnitude__7Point3dSFv();

由于缺乏this指针,所以静态成员函数差不多等同于非成员函数。

🔍 相关推荐

战队信息
365bet网络足球赌博

战队信息

📅 07-29 👀 9855