关于《深度摸索C++工具模子》搁浅了半个月,本日继承啃这个骨头,我的进修进入了第四章,函数的语意学。先做个温习C++支持三种成员函数:静态、虚、和非静态。每一种函数的挪用方法都差异,虽然他们的浸染也会有区别,一般来说我们只要把握按照我们的需要正确的利用这三种范例的成员函数便可以了,至于内部是如何运做的我们可以不知。可是《深度摸索C++工具模子》正是让我们对这些不知道的对象举办深度摸索的一本书。通过前面的进修,我想我知道了一些以前不知道的对象,可是感受并没有提高几多,也许是我对此书的进修还逗留在一个较量浮浅的条理上吧。我想我应该会抽时间再看几遍。有些跑题了,因为雷神想说明一下,这些条记只是雷神看书是的一些想法的记录,假如你再看仅供参考,因为我本人好象也只摸索了不是很深的水平。 我们的在设计和利用类时最常用的便长短静态成员函数,利用成员函数是为了封装和埋没我们的数据,我想这是成员函数和外部函数的最明明的区别。可是他们的效率是否有差异呢?我们不会想为了掩护我们的数据而利用成员函数,最后确导致效率低落的功效。让我们看看非静态成员函数在实际的执行时被编译器搞成了什么样子。
float magnitude3d(const Point3d *_this){…}
//这是一个外部函数,它有参数。暗示它间接的取得坐标(Point3d)成员。
float Point3d::mangnitude3d() const {…}
//这是一个成员函数,它直接取得坐标(Point3d)的成员。
外貌上看,好像成员函数的效率高许多,但实际上他们的效率真的想我们想象的那样吗?非也。实际上一个成员函数被内部转化成了外部函数。
1、 一个this指针被插手到成员函数的参数中,为的是可以或许使类的工具挪用这个函数。
2、 将对所有非静态数据成员的存取操纵改为由this来存取。
3、 对函数的名称举办从头的处理惩罚,使它成为措施中唯一无二的。
这时后,颠末以上的转换,成员函数已经成为了非成员函数。
float Point3d::mangnitude3d() const {…}//成员函数将被酿成下面的样子
//伪码
mangnitude3d__7Point3dFv(register Point3d * const this)
{
return sqrt(this->_x * this->x+
this->_y * this->y+
this->_z * this->z);
}
挪用此函数的操纵也被转换
obj. mangnitude3d()
被转换成:
mangnitude3d__7Point3dFv(*obj);
怎么样看出来了吧,和我们开始声明的非成员函数没有区别了。因此得出结论:两个铁球同时落地。
一般来说,一个成员的名称前面会被加上类的名称,形成独一的定名。实际上在对成员名称做处理惩罚时,除了加上了类名,还会将参数的链表一并加上,这样才气担保功效是唯一无二的。
我们在来看看静态成员函数。我们有这样的观念,成员函数的挪用必需是用类的工具,象这样obj.fun();可能这样ptr->fun().但实际上,只有一个或多个静态数据成员被成员函数存取时才需要类的工具。类的工具提供一个指针this,用来将用到的非静态数据成员绑定到类工具对应的成员上。假如没有用到任何一个成员数据,就不需要用到this指针,也就没有须要通过类的工具来挪用一个成员函数。并且我们还知道静态数据成员是在类之外的,可以被视做全局变量的,只不外它只在一个类的生命范畴内可见。(参考前面的条记)。并且一般来说我们会将静态的数据成员声明为一个非Public。这样我们便必需提供一个或多个成员函数用来存取这个成员。固然我们可以不依靠类的工具存取静态数据成员,可是这个可以用来存取静态成员的函数确实必需绑定在类的工具上的。为了越发好的办理这个问题,cfront2.0引入了静态成员函数的观念。
静态成员函数是没有this指针的。因为它不需要通过类的工具来挪用。并且它不能直接存取类中的非静态成员。而且不可以或许被声明为virtual,const,volatile.假如取得一个静态成员函数的地点,那么我们得到的是这个函数在内存中的位置。(非静态成员函数的地点我们得到的是一个指向这个类成员函数的指针,函数指针)。可以看到由于静态成员函数没有this指针,和非成员函数很是的相似。
有了前面几章的基本,好象这些描写领略起来也不很费劲,并且我们的思路可以随着书上所说的一路倾泻下来,这即是念书的兴趣地址了,假如一本书读起来都想读第一章时那样费劲,我想我读不下去的大概性会很高。
继承我们的进修,下面书上开始将虚函数了。我们知道虚函数是C++的一个很重要的特性,面向工具的多态即是由虚函数实现的。多态的观念是一个用一个public base class的指针(可能引用),寻址出一个派生类工具。虚函数实现的模子是这样。每一个类都有一个虚函数表,它包括类中有浸染的虚函数的地点,当类发生工具时会有一个指针,指向虚函数表。为了支持虚函数的机制,便有了“执行期多态”的形式。
下面这样。
我们可以界说一个基类的指针。
Point *ptr;
然后在执行期使他寻址出我们需要的工具。可以是
ptr =new Point2d;
#p#分页标题#e#
还可以是
ptr=new Pont3d;
ptr这个指针认真使措施在任那里所都可以回收一组由基类派生的范例。这种多态形式是消极的,因为它必需在编译时期完成。与之对应的是一种多态的努力形式,即在执行期完成用指针或引用查找我们的一个派生类的工具。
象下面这样:
ptr->z();
要想到达我们目标,这个函数z()应该是虚函数,而且还应该知道ptr所指的工具的真实范例,以便我们选择z()的实体。以及z()实体的位置,以便我们可以或许挪用它。这些事情编译器城市为我们做好,编译器是如何做的呢?
我们已知每一个类会有一个虚函数表,这个表中含有对应类的工具的所有虚函数实体的地点,而且大概会改写一个基类的虚函数实体。假如没有改写基类存在的虚函数实体,则会担任基类的函数实体,这还没完,还会有一个pure_virtual_called()的函数实体。每一个虚函数岂论是担任的照旧改写的,城市被指派一个牢靠的索引值,这个索引在整个担任体系中保持与特定的虚函数关联。
说明:当没有改写基类的虚函数时,该函数的实体地点是被拷贝到派生类的虚函数表中的。
这样我们便实现了执行期的努力多态。这种形式的特点是,我们从新到尾都不知道ptr指针指向了那一个工具范例,基类?派生类1?派生类2?我们不知道,也不需要知道。我们只需要知道ptr指向的虚函数表。并且我们也不知道z()函数的实体会被挪用,我们只知道z()函数的函数地点被放在虚函数表中的位置。
总结:在单一担任的体系中,虚函数机制是一种很有效率的机制。我们判定一个类是否支持多态,只需要看它有没有虚函数便可以了。 好了本日就到这里,雷神必需加速进修这本书的速度了,好象此刻也可以快一些了。