首页 > 代码库 > Virtual Member Functions & Static Member Function

Virtual Member Functions & Static Member Function

如果一个 normalize() 是一个 virtual member function, 那么以下的调用:

ptr->normalize();

将会被内部转化为:

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

其中:
vptr 表示由编译器生成的指针, 指向 virtual table, 它被安插在每一个声明有(或继承自) virtual functinos 的 class object 中。 事实上其名称也会被 mangled, 因为在一个复杂的 class 派生体系中, 可能存在多个 vptrs。
1 是 virtual table 的索引值, 关联到 nirmalize 函数。
第二个 ptr 表示 this 指针。
类似的道理, 如果 magnitude() 也是一个 virtual function,它在 normalize() 中的调用操作将被转化如下:

//register float mag = magnitude();register float mag = (*this->vptr[2] )(this);

此时, 由于 Point3d::magnitude() 是在 Point3d::normalize() 中被调用, 而后者已经由虚拟机制而决议妥当, 所以明确地调用 Point3d 实体会比较有效率, 并因此压制由于虚拟机制而产生的不必要的重复调用操作:

//明确的调用操作(explicit invocation) 会压制虚拟机制register float mag = Point3d::magnitude();

如果 magnitude() 声明为 inline 函数会更有效率。使用 class scope operator 明确调用一个 virtual function, 其决议方式会和 ninstatic member functino 一样:

register float mag = magnitude__7Point3dFv(this);

对于以下调用:

//Point3d obj;obj.normalize();

如果编译器把它转换为:

(*obj.vptr[1])(&obj);

虽然语意正确, 却没有必要, 因为经由 obj 调用的函数实体只可以是 Point3d::normalize() 经由一个 class object 调用一个 virtual function,这种操作应该总是被编译器像对待一般的 nonstatic member function 一样的加以决议:

//因为 normalize() 的归属无可争议normalize__7Point3dFv(&obj);

这项优化工程的另一个利益是 virtual function 的一个 inline 函数实体可以被扩展开来, 因而提供极大的效率意义。

Static Member Function
如果 Point3d::normalize() 是一个 staitc member function, 以下两个操作:

obj.;normalize();ptr->normalize();

将被转为一般的 nonmember 函数调用, 像这样:

//obj.normalize()normalize__7Point3dFv();//ptr->normalize__7Point3dFv();

在 C++ 引入 static member function 之前, 我想你很少看到下面这种怪异写法:

((Point3d*) 0 )->object_count();

其中的 object_count() 只是简单传回 _object_cout 这个 static data member. 这种习惯是如何演化来的呢?
在引入 static member function 之前, C++ 要求所有的 member functions 都必须 经由该 class object 来调用, 而实际上, 只有当一个或多个 nonstatic data members 在 member function 中被直接存取时, 才需要 class object. class object 提供了 this 指针给这种形式的函数调用使用, 这个 this 指针把在 member function 中村取得 nonstatic class member 绑定于 object 内对应的 members 之上, 如果没有任何一个 members 被直接存取, 事实上就不需要 this 指针, 因此也就没必要通过一个 class object 来调用一个 member function.
这么一来就在存取 static data members 时产生了一些不规则性. 如果 class 的设计者 把 static data member 声明为 nonpublic, 那么他就必须提供一个或多个 member functions 来存取该 member. 因此虽然你可以不靠 class object 来 存取一个 static member, 但其存取函数却得绑定于一个 class object 之上.
独立于 class object 之外的存取操作, 在某个时候特别重要: 当 class 设计者希望支持没有 class object 存在的情况(就像前述的 object_count() 那样) 时, 程序方法上的解决之道是很奇特的把 0 强制转型为一个class 指针, 因而提出一个 this 指针实体:

//函数调用的内部转换object_count((Point*) 0 );

至于在语言层面上的解决之道, 是由 cfront 所引入的 staticmember functions. Static member functions 的主要特性是他没有 this 指针, 以下的次要特性均源于其主要特性:
1. 它不能够直接存取其 class 中的 nonstatic members
2. 它不能够被声明为 const, volatile 后 virtual.
他不需要经由 class object 才被调用--虽然它大部分时候就是这么调用的...
member selection 语法的使用是一种符号上的便利, 它会被转化为一个直接调用操作:

if(Point3d::object_count() > 1)...

哦, 这个表达式仍然需要被评估求职

//转化, 以保存副作用(void)Foo();

一个 static member fucntion, 当然会被提出于 class 声明之外, 并给予一个经过 mangled 的适当名称, 例如:

unsigned intPoint3d::object_cout(){return _object_cout;}//会被转化为usnign intobject_cout__5Point3dSFv(){    return _object_cout__5Point3d;}

其中 SFv 表示它是个 static member function, 拥有一个空白 (void) 的参数链表(argument list).
如果取一个 static member function 的地址, 获得的将是其在内存中的位置, 也就是其地址,由于 static member function 没有 this 指针, 所以其地址的类型并不是一个指向 class member function 的指针, 而是一个 nonmember 函数指针, 也就是说:

&Point3d::object_cout();

会得到一个数值, 类型是:

usigned int (*)();

而不是:

unsigned int (Point3d::*)();

static member function 由于缺乏 this 指针, 因此差不多等于 nonmember function. 它提供了一个意想不到的好处:成为一个 callback 函数,使得我们得以将 C++ 和 C-based X Windows 系统结合, 它们也可以成功的用在线程函数身上.

Virtual Member Functions & Static Member Function