一,member function的调用方式
C++支持三种类型的member function:static、nonstatic和virtual,每一种类型被调用的方式都不同。
二,Nonstatic Member Function
C++的设计准则之一就是:nonstatic member function至少必须和一般的nonmember function有相同的效率。选择member function不应该带来什么额外的负担,这是因为编译器已将member函数实例转换为对等的nonmember函数实例,实际上member function被内化为nonmember的形式,下面就是转化的步骤:
1,改写函数的函数原型,以安插一个额外的参数到member function中,这个额外的参数被称为this指针。
2,将每一个对nonstatic data member的存取操作改为经由this指针来存取。
3,将member function重写成一个外部函数,函数名称经过"mangling"处理,使它在程序中成为独一无二的词汇。
三,Static Member Function
static member function的主要特征是它没有this指针,以下的次要特征都是根源于其主要特征。
1,不能够直接存储nonstatic members。
2,不能被声明为const、virtual。
3,它不需要经由class object才被调用,虽然大部分时候它是这样被调用的。
4,对static member function的调用会转换为一个直接调用操作
class Point{ public: static int object_count(){ return 10; } }; int main(){ Point obj; Point *pObj = &obj; obj.object_count(); pObject->object_count(); //上面两个对static member function的调用会转换下面这个直接调用操作 //Point::object_count() return 0; }
四,Virtual Member Function
如果normalize()是一个virtual member function,那么以下的调用:
ptr->normalize();
将会被内部转换为:
(*ptr->vptr[1])(ptr);
vptr表示由编译器产生的指针,指向virtual table。1 是virtual table slot的索引值,关联到normalize()函数。第二个ptr表示this指针。
五,多态
在C++中,多态表示"以一个public base class的指针(或引用),寻址出一个derived class object的意思"。
1,当一个类中声明有虚函数会发生什么事情?
(1),编译器会给这个类创建一个虚函数表,表中存放的是虚函数的地址。每一个虚函数都被指定一个固定的索引值,这个索引在整个继承体系中保持与特定的虚函数的关系。
(2),会给每个class object增加一个成员vptr,指向class所拥有的虚函数表。
2,当一个class派生自Point会发生什么什么事情?
(1),它可以继承base class所声明的virtual function实例。正确地说,该函数实例的地址被拷贝到derived class的virtual table的相应slot中。
(2),对base中的虚函数进行覆盖,这表示它自己的虚函数实例必须放在对应的slot中。
(3),加入新的virtual function。
3,如何确保调用到正确的虚函数?
假设有下面这个虚函数调用
ptr->normalize();
我们如何有足够的知识在运行时,调用正确的normalize()函数?
(1),在调用normalize()时,经由ptr可以获取该对象的virtual table。
(2),虽然我们不知道哪一个normalize()函数实例会被调用,但是我们知道每一个normalize()函数地址都被放在slot 1中。
(3),根据上面这些信息,编译器可将上面的调用转换为:
(*ptr->vptr[1])(ptr);