首先当我们设计一个基类的时候,对于派生类的需求可能有以下几种:
1)派生类只继承基类的接口,即函数的声明。
2)派生类同时继承函数的接口和实现,同时希望能够重写自己的版本(多态)
3)派生类同时继承函数接口和实现,但是不可以覆写任何东西。
我们接下来具体来说明上面各种选择之间的差异:
class Shape{
public:
virtual void draw() const = 0;
virtual void error(const std::string &msg);
int objectID() const;
...
};
class Rectangle:public Shape{...};
class Ellipse:public Shape{...};
先说明一下,
virtual void draw() const = 0;
是纯虚函数,纯虚函数的存在使得Shape类变成一个抽象类,即不能够实例化出对象。
纯虚函数的声明:virtual +函数返回值+函数名 ,在函数名后紧跟=0.
这样客户就不能够实例化Shape类了,因为它属于抽象类,但是它依然影响着以public继承方式继承的派生类。因为成员函数的接口总是被继承,public继承意味着is-a的关系。即保证任何一个对基类为真的事件,一定也对其派生类为真。
纯虚函数两个最基本特征:
1) 他们在抽象类中通常没有定义
2)他们必须被任何“继承了它们”的具体class重新声明
所以:
声明一个pure virtual函数的目的是为了让derived class只继承函数的接口。
virtual void error(const std::string &msg);
上面的函数是一个普通的虚函数(不是纯虚函数),通常来讲,派生类函数可以继承其函数接口,但是相对于纯虚函数来说,虚函数可以为程序提供一份实现代码,派生类可以覆写这个方法。
所以:
声明简朴的(非纯)虚函数的目的,是让派生类继承该函数的接口和缺省实现。
如果成员函数是一个non-virtual函数,表示它不打算在derived class中有不同的行为,实际上一个non-virtual成员函数所表现的不变性凌驾于其特异性。因为他表示无论derived class变得多么的特异化,他的行为都不可以改变。
所以:
声明non-virtual 函数的目的是为了令derived class继承函数的接口以及一份强制的代码实现。
pure virtual函数,simple(impure) virtual函数,non-virtual函数之间的差异,使得你可以精确的指定你想要派生类继承的东西,只继承接口、或是继承接口和一份缺省实现、或是继承接口和一份强制实现。由于这些不同类型的声明意味着根本不相同的事情,当你声明你的成员函数的时候,必须谨慎选择。