封装->继承->多态
- 普通虚函数 check
- 虚析构函数 check
- 纯虚函数 check
- 抽象类 check
- 接口类 check
- RTTI
- 异常处理
- 隐藏 覆盖 check
- 早绑定 晚绑定 check
- 虚函数表 check
纯虚函数
类中,一个虚函数没有函数体,直接=0。称为纯虚函数。如下:
1 | class Shape{ |
上一篇中提到,一个类中因为有虚函数,所以一定有虚函数表指针,当然也有虚函数表。如果类中虚函数是一个普通的虚函数,这个虚函数的地址存储在虚函数表中。如果是纯虚函数,则在虚函数表中存储0,即该函数没有实现,没有函数体,所以自然就没有地址。
抽象类
纯虚函数一定是某个类的成员函数。包含纯虚函数的类称作抽象类。
含有一个或多个纯虚函数的类叫做抽象类。
抽象类是不被允许实例化对象的。
抽象类的子类也可以是抽象类。
Person类太抽象,所以设计成抽象类:
1
2
3
4
5
6class Person{
public:
Person(string name);
virtual void work()=0;
virtual void printInfo()=0;
};Worker
类作为子类还是抽象,仍然是抽象类:1
2
3
4
5
6
7
8class Worker:public Person{
public:
Worker(string name);
virtual void work()=0;
virtual void printInfo(){ cout<<m_strName; };
private:
string m_strName;
};抽象类的子类,只有把抽象类中的所有纯虚函数都做了实现,那么这个子类才可以实例化对象:
1
2
3
4
5
6
7
8class Dustman:public Worker{
public:
Worker(string name);
virtual void work(){ cout<<"Cleaning"; };
virtual void printInfo(){ cout<<m_strName; };
private:
string m_strName;
};
一个实例:Person
被设计为一个抽象类,它work
可是什么不好说:
1 | class Person{ |
Worker
类还是抽象,具体做什么呢:
1 | // 还是抽象类 |
Dustman
就具体了,做清洁的一类工人:
1 | class Dustman:public Worker{ |
接口类
只含有纯虚函数的类称为接口类。即这个类中没有任何数据成员,只有成员函数,而这仅有的成员函数又都是纯虚函数。
接口类长这样:
1 | class Shape{ |
“只有纯虚函数”真的是只有纯虚函数。
使用时,接口类表达一种能力或协议。接口类要被继承,且所有纯虚函数要被实现。最常使用方式如下例:
两个接口类:
1 | // 饮食习惯 |
一个普通类:
1 | // ID 即姓名 |
Fighter
是一个更具体的类,分别继承上述两个接口和一个普通类,并且实现所有的纯虚函数:
1 | class Fighter: public ID, public Diet, public Training{ |
最近的子类(在本例中也是唯一的子类)Fighter
继承了ID
, 表示Fighter
有ID
类的姓名。而且继承了Diet
, 表示Fighter
有各自的饮食习惯。还继承了Training
类, 表示Fighter
有各自的训练方式。只是Fighter
的饮食和训练方式要自己定义。
最终使用的是那个没有被继承的类Fighter
:
1 | void match(Fighter* candidate1, Fighter* candidate2){ |
该实例是接口类的常用形式。