本文系整理Effective C++中的条款34
首先当我们设计一个基类的时候,对于派生类的需求可能有下面几种
- 派生类只继承基类的接口(即函数的声明);
- 派生类同时继承接口和实现,并且希望能够重写(多态)自己的版本
- 派生类同时继承接口和实现,但是不允许重写任何东西
说这些晦涩难懂的文字,一时半会不好理解,下面分别举实例,用代码来解读这三种需求。
下面是一个展现绘图程序中各种几何图形的class继承体系:
class Shape
{
public:
//纯虚函数
virtual void draw()const = 0;
//普通的虚函数
virtual void error(const std::string& msg);
普通函数
int objectID()const;
...
};
class Rectangle:public Shape{
...};
class Ellispse:public Shape{
...};
这里首先说下,因为virtual void draw()const = 0;
是一个纯虚函数,从而使Shape类变为一个抽象类,即不能实例化出对象。
纯虚函数的声明:virtual + 函数返回值+函数名,在函数的后面紧跟=0。
这样就导致客户不能实例化出Shape的对象,只能实例化出其派生类的对象。但是基类还是影响了所有以public方式继承它的派生类,因为成员函数的接口总是被继承,public继承意味着is-a的关系。即保证任何一个对基类为真的事件,一定也对其派生类为真。
pure virtual(纯虚函数)的特性:
- 在抽象类中通常没有定义
- 必须被任何”继承了它们”的具体class重新声明
这就意味着声明一个pure virtual函数的目的是为了让派生类只继承函数的接口
但是令人意外的是,我们竟然可以为pure virtual函数提供定义,也就是说你可以为Shape::draw供应一份实现代码,c++并不会发出怨言,但是调用它的唯一途径是”调用时指明其class名称”
如下实例:
Shape* ps = new Shape; <