1. 找出所有子类共通的操作行为;
2. 找出哪些操作行为必须根据不同的派生类而有不同的实现方式;
3. 找出每个操作行为的访问层级。
所有子类的共通的操作行为,所代表的是基类的公有接口。
class num_sequence{
public:
int elem(int pos);
//elem(pos):返回pos位置上的元素
void gen_elems(int pos);
//gen_elems(pos):产生直到pos位置的所有元素
const char* what_am_i() const;
//what_am_i():返回确切的数列类型
ostream& print(ostream &os=cout) const;
//print(os):将所有元素写入os
bool check_integrity(int pos);
//检查pos是否为有效位置
static int max_elems();
//max_elems():返回所支持的最大位置值
必须根据不同的派生类而有不同的实现方式的操作行为们,应该成为整个类继承体系的虚函数。
注意:静态成员函数无法被声明为虚函数。
public
;private
,即使是该基类的派生类,亦无法访问到基类中的private成员;protected
。//重新修整num_sequence基类的定义
clss num_sequence{
public:
virtual ~num_sequence(){};
virtual int elem(int pos) const = 0; //赋值为0即纯虚函数
virtual const char* what_am_i() const = 0;
static int max_elems(){return _max_elems;}
virtual ostream& print(ostream &os=cout) const = 0;
protected:
virtual void gen_elems(int pos) const = 0;
bool check_integrity(int pos) const;
const static int _max_elems = 1024;
纯虚函数:
- 每个虚函数,要么有定义,要么将虚函数赋值为0,即变成了纯虚函数,无实质的意义;
- 任何类如果声明有一个(或多个)纯虚函数,其接口(public/private/protected)就不完整了(纯虚函数没有函数定义),程序无法为它产生任何对象。这种类,只能作为派生类的子对象使用,而且前提是这些派生类必须为所有的虚函数提供确切的定义。
本例中的num_sequence基类并未声明任何数据成员,因为它只是为“数列继承体系”提供一个接口;其派生类必须自行设计自身的数据成员。
本例中的num_sequence基类没有任何的非静态数据成员需要进行初始化操作,也就无需设计构造函数,但需设计析构函数(凡基类定义一个/多个虚函数,应该要将基类的析构函数声明为虚函数)。
class num_sequence{
public:
virtual ~num_sequence(){};
//...
//不建议声明为纯虚函数,最好是提供空白定义
至此,抽象基类的整个定义已完成,但是类本身并不完全,仅是为派生类提供了接口,每个派生类还需提供适当的实现细节,以补足基类。