虚函数
如果需要通过基类的指针指向派生类的对象,并访问某个与基类同名的成员,那么首先在基类中将这个同名函数声明为虚函数。这样就可以通过基类指针,使属于不同派生类的不同对象产生不同的行为,从而实现运行过程的多态。
如果你编写代码的时候,并不能确定调用的是基类的函数还是哪个派生类的函数时,你可以选择使用虚函数。
即在类的定义中使用virtual
关键字来限定函数成员,不过注意虚函数声明只能出现在类定义中的函数原型声明中,而不能在成员函数实现的时候。
代码如下:
#include <iostream>
using namespace std;
class Base1{ //基类Base1定义
public:
virtual void display() const; //虚函数
};
void Base1::display() const{
cout<<"Base1::display()"<<endl;
}
class Base2:public Base1{ //公有派生类Base2定义
public:
virtual void display() const; //覆盖基类的虚函数
};
void Base2::display() const{
cout<<"Base2::display()"<<endl;
}
class Derived:public Base2{ //公有派生类Derived定义
public:
virtual void display() const; //覆盖基类的虚函数
};
void Derived::display() const{
cout<<"Derived::display()"<<endl;
}
void fun(Base1 *ptr){ //参数为指向基类对象的指针
ptr->display(); //“对象指针->成员名”
}
int main(){
Base1 base1; //定义对象
Base2 base2;
Derived derived;
fun(&base1); //用Base1对象的指针调用fun函数
fun(&base2); //用Base2对象的指针调用fun函数
fun(&derived); //用Derived对象的指针调用fun函数
return 0;
}
注意为了清楚地提示这是一个虚函数,我在两个派生类中都使用了virtual
关键字。
运行结果:
子类可以重写父类的虚函数实现子类的特殊化。
从上例看出,在fun函数中使用基类类型的指针ptr
可以指向Base1,Base2还有Derived的display()
函数成员,使程序更加高效简洁。
假设我把其中的virtual都去掉,运行起来就是如下的场景:
因为去掉了virtual
,程序根据其是Base1的指针全部调用了Base1的display
方法执行。
我来斗胆总结一下:不使用virtual
,程序根据引用、指针类型选择方法;使用virtual
,程序根据对象类型来选择方法。基类派生类函数名相同功能不同时最好使用virtual
。
纯虚函数
有时候,基类中的虚函数是为了派生类中的使用而声明定义的,其在基类中没有任何意义,此类函数我们叫做纯虚函数。带有纯虚函数的类称为抽象类。
纯虚函数与一般虚函数成员的原型书写不同,后面加了“=0”
。声明为纯虚函数之后,基类就可以不再给出函数的实现部分,纯虚函数的函数体就只能交给派生类来给出了。这一点较于虚函数更好理解。
代码如下:
#include <iostream>
using namespace std;
class Base1{
public:
virtual void display() const=0; //纯虚函数
};
class Base2:public Base1{
public:
virtual void display() const; //覆盖基类的虚函数
};
void Base2::display() const{
cout<<"Base2::display()"<<endl;
}
class Derived:public Base2{
public:
virtual void display() const; //覆盖基类的虚函数
};
void Derived::display() const{
cout<<"Derived::display()"<<endl;
}
void fun(Base1 *ptr){ //参数为指向基类对象的指针
ptr->display(); //“对象指针->成员名”
}
int main(){
Base2 base2;
Derived derived;
fun(&base2);
fun(&derived);
return 0;
}
运行结果:
程序中类Base1,Base2和Derived属于同一个类族,抽象类Base1通过纯虚函数为整个类族提供了通用外部接口。抽象类的Base1类型指针也可以指向任何一个派生类对象。在fun
函数中通过基类Base1指针ptr
可访问到ptr
指向的派生类Base2,Derived类对象成员,这样就实现了对同一类族的对象进行统一的多态处理。