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

C++学习笔记――多态性和虚函数

2009-04-26 22:25 381 查看
多态性实现了接口和实现的分离。
捆绑:将函数体和函数调用相联系成为捆绑。分为早捆绑和晚捆绑,早捆绑在程序运行之前完成,晚捆绑反之。
C++中,虚函数实现晚捆绑。将基类的函数声明为virtual,对派生类的函数都将使用虚机制。实现运行时捆绑――晚捆绑。
实现:VTABLE&Vptr:
VTABLE:存放类中所有虚函数的地址
Vptr:指向VTABLE的指针,使函数通过基类指针调用虚函数时能匹配正确。
如:
Class Base
{
int param1;
public:
virtual void f(){ cout<<"base"<<endl;}
virtual int g(){ return 0 ;}
};
Class Derived:public Base
{
int param2;
public:
void f(){ cout << "deriverd"<< endl;}
int g(){ return 1; }
virtual string F(){return "derived";}
};
上面两个类的VTABLE分别为:

&Base::f
&Base::g
&Derived::f
&Dervived::g
&Derived::F
每当创建一个含有虚函数的类时,编译器就为这个类创建一个VTABLE,,并且在这个类中放置指向VTABLE首地址的指针Vptr。一旦VPTR被初始化为指向相应的VTABLE,对象就知道自己的类型。当通过基类地址调用一个虚函数时,如
Deriverd d;
Base * bptr = & d;
bptr-> g();
此时,虽然进行了向上类型转换,程序运行仍然调用派生类对象d的g()函数,返回1。程序通过基类指针bptr指向对象d的的首地址,由于VPTR存于对象中的相同位置,编译器能够取出对象d的VPTR,通过指针偏移获得函数g()的地址,进行调用,完成了晚捆绑。晚捆绑访问VTABLE,所以调用虚函数时有额外的开销,对函数调用的效率有所影响。
纯虚函数:将上面代码修改,如下:
Class Base

{

public:

virtual void f()=0;

virtual int g()=0;

};
基类的虚函数声明为“=0”的形式即声明为纯虚函数。纯虚函数可以没有定义,并且含有纯虚函数的类变成抽象类,不准生抽象类的对象。
派生类必须对基类所有的纯虚函数进行定义,否则仍然为抽象类,不能生成对象实例。
传值调用:对象切片问题
设存在函数 void function(Base b);函数接受基类对象b,如果声明一个派生类对象
Dervived d;
function(d);此时会发生向上类型转换,将派生类对象转换为Base类型的,对于Base类型的对象只有一个数据成员,而派生类的对象有两个,发生向上类型转换时,发生对象切片,派生类的私有数据成员param2丢失。如下表所示,分别为切片以前和切片以后的对象部分:
Derived Vptr
param1
param2
Derived Vptr
param1
虚机制不作用于构造函数和析构函数,在构造函数和析构函数中调用的虚函数都是函数的本地版本。对于构造函数,因为虚函数所属的子类对象可能还没有生成,析构函数反之,这时调用发生错误。
可以有纯虚的析构函数,并且纯虚的析构函数必须有定义。虚析构函数的主要作用是防止实例化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: