您的位置:首页 > 编程语言 > C语言/C++

c++多态性

2016-01-12 16:20 281 查看
C++多态性

两种表现形式:静态多态性 通过一般的函数重载来实现。

动态多态性 通过虚函数来实现。

静态多态性比较简单,主要动态多态性比较难理解。

动态多态性有两个条件:

1、在基类中必须使用虚函数、纯虚函数

2、调用函数时要使用基类的指针或引用。

只要在基类的成员函数前加上virtual,该成员函数就是虚函数,从基类派生出来的类的同名成员函数,不管前面是否有virtual,同样是虚函数,在虚函数的实现时,前面不能加virtual。

内联函数不能是虚函数,因为内联函数不能在运行时动态确定位置,即使虚函数在类的内部定义,但在编译的时候仍然看做是非内联的。

只有类的成员函数才能声明为虚函数,普通函数不能声明为虚函数。

静态成员函数不能是虚函数。



虚函数的原理:



普通函数的处理:

一个特定的函数都会映射到特定的代码,无论时编译阶段还是连接阶段,编译器都能计算出这个函数的地址,调用即可。

虚函数的处理:

被调用的函数不仅依据调用的特定函数,还依据调用的对象的种类。通常是由虚函数表(vtable)来实现的。

虚函数表的结构:

它是一个函数指针表,每一个表项都指向一个函数。任何一个包含虚函数的类都会有这样一张表。需要注意的是vtable只包含虚函数的指针,没有函数体。实现上是一个函数指针的数组。

虚函数表既有继承性又有多态性

每个派生类的vtable继承了它各个基类的vtable,如果基类vtable中包含某一项,则其派生类的vtable中也将包含同样的一项,但是两项的值可能不同。如果派生类重载(override)了该项对应的虚函数,则派生类vtable的该项指向重载后的虚函数,没有重载的话,则沿用基类的值。

每一个类只有唯一的一个vtable,不是每个对象都有一个vtable,每个对象都有一个指针,这个指针指向该类的vtable(当然,前提是这个类包含虚函数)。

那么,每个对象只额外增加了一个指针的大小,一般说来是4字节。

在类对象的内存布局中,首先是该类的vtable指针,然后才是对象数据。

在通过对象指针调用一个虚函数时,编译器生成的代码将先获取对象类的vtable指针,然后调用vtable中对应的项。

对于通过对象指针调用的情况,在编译期间无法确定指针指向的是基类对象还是派生类对象,或者是哪个派生类的对象

但是在运行期间执行到调用语句时,这一点已经确定,编译后的调用代码能够根据具体对象获取正确的vtable,调用正确的虚函数,从而实现多态性。

下面是通过基类的指针来调用虚函数时,所发生的一切:

step 1:开始执行调用 pA->run();(pA为基类指针,这里能判断到底是哪个对象)

step 2:取得对象的vtable的指针

step 3:从vtable那里获得函数入口的偏移量,即得到要调用的函数的指针

step 4:根据vtable的地址找到函数,并调用函数。

step 1和step 4对于一般函数是一样的,虚函数只是多了step 2和step 3。

基类和派生类是共用一表,还是各有各的表(物理上)?

答:基类和派生类是各有各的表,也就是说他们的物理地址是分开的,基类和派生类的虚表的唯一关联是:当派生类没有实现基类虚函数的重载时,派生类会直接把自己表的该函数地址值写为基类的该函数地址值.

来自: http://hi.baidu.com/scuxy06/blog/item/5a8140d61e5dbb2507088b5c.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: