第4章 Function 语意学1: Member的各种调用方式
一、Nonstatic member functions
C++ 的设计准则之一就是:nonstatic member function 至少必须和一般的nonmember function 有相同的效率。也就是说,如果我们要在以下两个函数之间作选择:
float magnitude3d( const Point3d * this ) { ... }
float Point3d::magnitude3d() const { ... }
那么选择 member function 不应该带来什么额外负担。这是因为编译器内部已将member 函数实体”转换为对等的“nonmember 函数实体。转化步骤:
1.引入形参this
// non-const nonstatic member 之增长过程Point3d
Point3d::magnitude( Point3d *const this )
2.对nonstatic data member 的存取操作改成经由this
return sqrt(
this->_x * this->_x +
this->_y * this->_y +
this->_z * this->_z);
3.将此member function 通过 mangling 改名
extern magnitude_7Point3dFv(register Point3d *const this );
现在这个函数已经被转换好了,而其每一个调用操作也都必须转换。于是:
obj .magnitude () ;
// 变成了:
magnitude_7point3dFv( &obj );
二、Virtual member functions
如果 normalize()是一个 virtual member function,那么以下的调用将会被内部转化为:
ptr->normalize();
//
( * ptr->vptr[ 1 ])( ptr );
其中:
-
vptr 表示由编译器产生的指针,指向 virtual table,它被安插在每一个“声明有(或继承自)一个或多个 virtual functions”的 class object 中。
-
1 是 virtual table slot 的索引值,关联到 normalize()函数。
-
第二个 ptr 表示 this 指针。
对于以下调用:
// Point3d obj;
obj.normalize();
如果编译器把它转换为:
( * obj->vptr[ 1 ])( &obj );
可以,却没有必要。应该像对待nonstatic member function 一样加以决议:
normalize_7Point3dFv( &obj );
三、Static Member Functions
编译器处理起来就和一个nonmember function一样
然后简单介绍了为什么会出现Static Member Functions。
首先,对于member data的存取,编译器需要走this指针;
其次, static 数据不是存放在类对象中,所以存取数据可以不走 this 指针;
而 static 一般建议使用 nopublic 的方式来声明,并通过一些public的function来存取,这样我们可以避免对象的生成,直接通过类静态函数进行访问。所以会出现下面这种存取方式:
(( Point3d* ) 0 )->object_count();
至于语言层面上的解决之道,是由 cfront 2.0所引人的 static memberfunctions。Static member functions 的主要特性就是它没有 this 指针。以下的次要特性统统根源于其主要特性:
-
它不能够直接存取其 class 中的 nonstatic members.
-
它不能够被声明为 const、volatile 或 virtual。
-
它不需要经由 class obiect 才被调用---虽然大部分时候它是这样被调用的!
如果取一个 static member function 的地址,获得的将是其在内存中的位置也就是其地址。由于 static member function 没有 this 指针,所以其地址的类型并不是一个“指向 class member function 的指针”,而是一个“nonmember 函数指针”。也就是说:
&Point3d::object count();
会得到一个数值,类型是:
unsigned int (*)();
而不是:
unsigned int ( Point3d::* )();