虚函数:
定义:
虚函数必须是基类的非静态成员函数,其访问权限可以是protected或public,在基类的类定义中定义虚函数的一般形式:
virtual 函数返回值类型 虚函数名(形参表)
{ 函数体 }
作用:
虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。
当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。
简单的理解就是:
可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时,基类指针调用其虚成员函数,则会调用其真正指向对象的成员函数,
而不是基类中定义的成员函数(只要派生类改写了该成员函数)。若不是虚函数,则不管基类指针指向的哪个派生类对象,调用时都 会调用基类中定义的那个函数。
虚函数表示函数是以间接的方式被调用,而不是由一个固定的函数入口地址来调用,一个函数调用可以对应不同的函数入口地址。
虚函数除了不能作为内联函数外,它遵循普通成员函数的所有语法规则。
函数声明语法:virtual return_type name( arguments );
在函数的定义部分和它的派生类的声明部分无需重复使用virtual关键字,它的所有派生类都保持virtual类型。
把函数转变为虚函数的作用是为了配合通过基类指针访问某一对象的操作。
如果在派生类里没有对某一函数进行重写,也就不必把此函数声明成虚函数。在进行函数调用时,虚函数的表现要略逊于普通函数,而且它也比代码相同的实函数占据较多的内存空间。
定义虚函数的限制:
(1)非类的成员函数不能定义为虚函数,类的成员函数中静态成员函数和构造函数也不能定义为虚函数,但可以将析构函数定义为虚函数。实际上,优秀的程序员常常把基类的析构函数定义为虚函数。因为,将基类的析构函数定义为虚函数后,当利用delete删除一个指向派生类定义的对象指针时,系统会调用相应的类的析构函数。而不将析构函数定义为虚函数时,只调用基类的析构函数。
(2)只需要在声明函数的类体中使用关键字“virtual”将函数声明为虚函数,而定义函数时不需要使用关键字“virtual”。
(3)当将基类中的某一成员函数声明为虚函数后,派生类中的同名函数自动成为虚函数。
(4)如果声明了某个成员函数为虚函数,则在该类中不能出现和这个成员函数同名并且返回值、参数个数、类型都相同的非虚函数。在以该类为基类的派生类中,也不能出现这种同名函数。
例子:
class A{
public:
void print(){ cout<<;”Thisis A”<<endl;}
};
class B:public A{
public:
void print(){ cout<<;”Thisis B”<<endl;}
};
//第一种,一般函数
int main(){ //为了在以后便于区分,我这段main()代码叫做main1
A a;
B b;
a.print();
b.print();
}
输出:This is A
This is B
//第二种指针对象调用
int main(){ //main2
A a;
B b;
A*p1=&a;
A* p2=&b;
p1->print();
p2->print();
}
输出:This is A
This is A
//虚函数
class A{
public:
virtual voidprint(){ cout<<;”This is A”<<endl;}
};
class B:public A{
public:
void print(){ cout<<;”Thisis B”<<endl;}
};
int main(){ //main2
A a;
B b;
A* p1=&a;
A* p2=&b;
p1->print();
p2->print();
}
输出:This is A
This is B
纯虚函数:
virtual 函数名=0
父类不实现,完全由子类去实现
如果一个类包含了纯虚函数,称此类为抽象类。