虚函数
首先分享一篇关于《虚函数》很生活的理解的博文:http://blog.chinaunix.net/uid-25749806-id-321984.html
定义:在某基类中声明为 virtual 并在一个或多个派生类中被重新定 义的成员函数。
语法: virtual 函数返回类型 函数名 (参数表) { 函数体 }
用途:实现多态性,通过指向派生类的基类指针,访问派生类中同名覆盖成员函数。
虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义(形式也是:
virtual 函数返回值类型 虚函数名(形参表){ 函数体 }),在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。
实现动态联编需要三个条件:
1、 必须把需要动态联编的行为定义为类的公共属性(public)的虚函数。
2、 类之间存在子类型关系,一般表现为一个类从另一个类公有派生而来。
3、 必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数。
举例如下:
class Animal
{
public:
Animal() { cout<<"I am an Animal!"<<endl;}
virtual void Food(){cout<<"Animal eat Something."<<endl;}
~Animal() {cout<<"Kill Animal"<<endl;}
};
class Tiger:public Animal
{
public:
Tiger() { cout<<"I am a Tiger!"<<endl;}
~Tiger() {cout<<"Kill Tiger"<<endl;}
virtual void Food(){cout<<"Tiger eat Meat."<<endl;}
};
class Bird:public Animal
{
public:
Bird() { cout<<"I am a Bird!"<<endl;}
~Bird() {cout<<"Kill Bird"<<endl;}
virtual void Food(){cout<<"Bird eat Worm."<<endl;}
};
main函数:
int main()
{
Animal a,*p_a;
Tiger t;
Bird b;
cout<<endl;
a.Food();
t.Food();
b.Food();
cout<<endl;
p_a = &t;
p_a->Food();
p_a = &b;
p_a->Food();
cout<<endl;
return 1;
}
I am a Animal! I am a Animal! I am a Tiger! I am a Animal!I am a Bird!Animal eat Something. Tiger eat Meat. Bird eat Worm.
Tiger eat Meat. Bird eat Worm.
Kill Bird Kill Animal Kill Tiger Kill Animal Kill Animal
在这个例子,看上面三个必须是怎么实现的。
1.公共属性函数
在基类Animal里,Food( )的声明:
virtual void Food(){cout<<"Animal eat Something."<<endl;}
它属于public公有的。
2.子类型关系
Tiger b、Bird b都是基类Animal的派生子类。
3.基类指针
Animal ×p_a 就是这里的基类指针。
(1)非类的成员函数不能定义为虚函数,类的成员函数中静态成员函数和构造函数也不能定义为虚函数,但可以将析构函数定义为虚函数。实际上,优秀的程序员常常把基类的析构函数定义为虚函数。因为,将基类的析构函数定义为虚函数后,当利用delete删除一个指向派生类定义的对象指针时,系统会调用相应的类的析构函数。而不将析构函数定义为虚函数时,只调用基类的析构函数。
(2)只需要在声明函数的类体中使用关键字“virtual”将函数声明为虚函数,而定义函数时不需要使用关键字“virtual”。
(3)如果声明了某个成员函数为虚函数,则在该类中不能出现和这个成员函数同名并且返回值、参数个数、参数类型都相同的非虚函数。在以该类为基类的派生类中,也不能出现这种非虚的同名同返回值同参数个数同参数类型函数。