首先:强调一个概念
定义一个函数为虚函数,不代表函数为不被实现的函数。
定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。
定义一个函数为纯虚函数,才代表函数没有被实现。
定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。
虚函数
我们首先举一个例子,如下所示
class A
{
public:
virtual void foo()
{
cout<<"A::foo() is called"<<endl;
}
};
class B:public A
{
public:
void foo()
{
cout<<"B::foo() is called"<<endl;
}
};
int main(void)
{
A *a = new B();
a->foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的!
return 0;
}
虚函数只能借助于指针或者引用来达到多态的效果。这个时候我们就疑惑了,为什么要用父类指针指向子类对象呢?直接定义子类对象不好吗?
那么这里我来说一个场景,你接到老板的任务,需要使用厂家的SDK实现一个功能,而厂家的一个put函数是私有的,而是这个函数和你的使用场景有些不同,需要重写。而你首先继承了厂家的Father的类,然后重写了Put函数,结果运行不是你想要的。
#include<iostream>
using namespace std;
class Father
{
void Put()
{
cout<<"父类Put函数"<<endl;
}
public:
void Show()
{
Put();
}
};
class Son:public Father
{
void Put()
{
cout<<"子类Put函数"<<endl;
}
};
int main()
{
Son a;
a.Show();
}
运行结果为:父类Put函数
这个时候你又要重写一个show函数,上述代码还算简单,如何代码间耦合嵌套比较深,那么就相当于重新写了一个新的类,而不需要继承了,这样就显得麻烦了。
纯虚函数
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加 =0:
virtual void funtion1()=0
为什么要这样呢?
- 为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。
- 在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。
声明了纯虚函数的类是一个抽象类。所以,用户不能创建类的实例,只能创建它的派生类的实例。
纯虚函数最显著的特征是:它们必须在继承类中重新声明函数(不要后面的=0,否则该派生类也不能实例化),而且它们在抽象类中往往没有定义。