1. 背景
OOP面向对象程序设计的核心是数据抽象,继承和动态绑定。前面的文章我们介绍了使用virtual的虚类实现动态绑定的多态,有时候我们在做抽象时,对于抽象的实体不想让被人实例化,虚类没有这个功能,我们Java里面我们有抽象类,有接口来抽象一个实体的行为,而不允许被实例化,C++有没有这样的功能呢?C++怎么实现抽象类呢?
2. 纯虚函数
介绍抽象类之前我们先了解下纯虚函数:我们通过在函数体的位置,即在声明语句的分号之前,书写 = 0 就可以将一个虚函数说明为纯虚函数。和普通的虚函数不一样,一个纯虚函数无需定义。而且 = 0 只能出现在虚函数声明语句处:
class IBird { public: void fly() = 0; }
我们也可以为纯虚函数提供定义,不过函数体必须定义在类的外部,不能在类的内部为一个=0的函数提供函数体。
派生类如果定义了一个函数与基类中虚函数的名字相同但是形参列表不同,这是合法的,但是很可能不符合我们的预期。特别是在继承纯虚函数时,可能因为形参列表不匹配导致声明了新的函数,而纯虚函数没有被真正实现,怎么让编译器帮助我么实现这一点呢?
在C++11新标准中,我们可以使用override关键字来说明子类中的虚函数。如果使用override标记了某个函数,但是这个函数又没有覆盖已存在的虚函数,编译器就直接报错了。
3. 抽象基类
了解了纯虚函数后我们就可以定义抽象类了:含有纯虚函数的类是抽象基类。抽象基类负责定义接口,而后续的其他类可以覆盖这个接口。
我们不能直接创建一个抽象基类的对象,子类构造函数只初始化它的直接基类,这个和Java类似,只在子类的构造中调用super初始化直接子类。
抽象基类的设计可以替代我们Java中的接口和抽象类,如果只定义行为,就类似于Java中的接口,如果包含了数据则可以类比成Java中的抽象类。
4. 总结
通过使用数抽象,我们可以将类的接口与实现分离;使用继承,可以定义相似的类型并对其相识关系建模;使用动态绑定,可以在一定程度上忽略相识类型的区别,以统一的方式使用对象。纯虚函数是实现抽象基类的基础。本文我们介绍了纯虚函数和抽象基类,这块语法上本身比较简单,下一篇我们介绍继承时的访问控制。