CPP学习之——复杂的抽象结构(16.7)

一 概述

本节介绍复杂的抽象类,并结合实例进行分析说明

二 分析说明

  • 这样我们就有了两个抽象类,第一个抽象类是动物类,它派生出两个类,一个鸟类,一个哺乳动物类,在鸟类中我们将6个方法全部覆盖,这样鸟类就不再是一个抽象类,它可以创建自己的对象,但是由于哺乳动物类中只覆盖了一个propagate()繁殖方法,其他保持不变,所以它仍然是一个抽象类,或者说是个接口类,它不能创建自己的对象,但是可以派生具有哺乳动物类繁殖方法的其他类,比如说人类和猪类,假如人类和猪类将哺乳动物类从动物类继承过来的五个未被覆盖的纯虚函数全部覆盖掉的话,那么它们就可以创建自己的对象,否则的话,它们仍然是抽象类

三 示例演示及结果输出

3.1 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include<iostream>
using namespace std;
class Animal
{
private:
int itsage;
public:
Animal(int);
virtual ~Animal(){cout<<"析构动物"<<endl;}
virtual int GetAge(){return itsage;}
virtual void Sleep()=0;
virtual void Propagate()=0;
virtual void Move()=0;
virtual void Body()=0;
virtual void Eat()=0;
virtual void Show()=0;
};
Animal::Animal(int age):itsage(age)
{
cout<<"创建动物.."<<endl;
}
class Mammalia:public Animal
{
public:
Mammalia(int age):Animal(age){cout<<"创建哺乳类.."<<endl;}
virtual ~Mammalia(){cout<<"析构哺乳类.."<<endl;}
virtual void Propagate(){cout<<"哺乳类是胎生动物,通过胚胎来繁殖后代。"<<endl;}

};
class Bird:public Animal
{
public:
Bird(int age):Animal(age){cout<<"创建鸟类.."<<endl;}
virtual ~Bird(){cout<<"析构鸟类.."<<endl;}
virtual void Sleep(){cout<<"鸟类喜欢站着睡觉。"<<endl;}
virtual void Eat(){cout<<"极个别鸟类喜欢吃肉,其他都吃素。"<<endl;}
virtual void Propagate(){cout<<"鸟类是卵生动物,通过排卵来繁殖后代。"<<endl;}
virtual void Move(){cout<<"鸟类可以飞。"<<endl;}
virtual void Body(){cout<<"鸟类体表被覆羽毛,前肢变为翼。"<<endl;}
virtual void Show(){cout<<"鸟类的一般寿命为:"<<GetAge()<<endl;}
};
class Human:public Mammalia
{
public:
Human(int age):Mammalia(age){cout<<"创建人类.."<<endl;}
virtual ~Human(){cout<<"析构人类.."<<endl;}
virtual void Sleep(){cout<<"人类要在床上睡觉。"<<endl;}
virtual void Eat(){cout<<"大多数人不吃生食。"<<endl;}
virtual void Propagate(){cout<<"人类通过胚胎繁殖后代。"<<endl;}
virtual void Move(){cout<<"人类靠两条腿走路。"<<endl;}
virtual void Body(){cout<<"人类体表无毛。"<<endl;}
virtual void Show(){cout<<"人类的一般寿命为:"<<GetAge()<<endl;}
};
class Pig:public Mammalia
{
public:
Pig(int age):Mammalia(age){cout<<"创建猪类.."<<endl;}
virtual ~Pig(){cout<<"析构猪类.."<<endl;}
virtual void Sleep(){cout<<"猪喜欢在烂泥里睡觉。"<<endl;}
virtual void Eat(){cout<<"猪是杂食类动物。"<<endl;}
virtual void Propagate(){cout<<"猪也通过胚胎繁殖后代。"<<endl;}
virtual void Move(){cout<<"猪靠四条腿走路。"<<endl;}
virtual void Body(){cout<<"猪体表有毛。"<<endl;}
virtual void Show(){cout<<"猪因为要被人宰了吃,所以一般寿命为:"<<GetAge()<<endl;}
};
int main()
{

Animal *p=0;
int choice;
bool quit=false;
while(choice<4)
{
cout<<"(1)猪类(2)人类(3)鸟类(0)退出";
cin>>choice;
switch(choice)
{
case 0:quit=true;
break;
case 1:p=new Pig(1);
break;
case 2:p=new Human(80);
break;
case 3:p=new Bird(50);
break;
default:cout<<"请输入0到3之间的数字";
break;

}
if(quit)
{
break;
}
p->Show();
p->Eat();
p->Propagate();
p->Move();
p->Sleep();
p->Body();
cout<<endl;
delete p;
}
return 0;
}

3.2 输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
(1)猪类(2)人类(3)鸟类(0)退出1
创建动物..
创建哺乳类..
创建猪类..
猪因为要被人宰了吃,所以一般寿命为:1
猪是杂食类动物。
猪也通过胚胎繁殖后代。
猪靠四条腿走路。
猪喜欢在烂泥里睡觉。
猪体表有毛。

析构猪类..
析构哺乳类..
析构动物
(1)猪类(2)人类(3)鸟类(0)退出2
创建动物..
创建哺乳类..
创建人类..
人类的一般寿命为:80
大多数人不吃生食。
人类通过胚胎繁殖后代。
人类靠两条腿走路。
人类要在床上睡觉。
人类体表无毛。

析构人类..
析构哺乳类..
析构动物
(1)猪类(2)人类(3)鸟类(0)退出

3 总结

从上例中我们总结出:

  • 一个抽象基类仍然可以派生出抽象类,只要该类没有把纯虚函数全部覆盖掉,派生出的抽象类,假如其子类没有将它的纯虚函数全部覆盖掉,那么该子类也是抽象类
  • 假如确定某个基类的纯虚函数一定会被其所有的派生类覆盖掉,那么不如将其设置为纯虚函数
  • 最后要注意的是:不要试图去创建一个抽象类的对象

四 慎用多重继承

  • 虽然多重继承比单一继承有很多优点,但是由于虚基类的定义很复杂,所以很多程序员还是不愿意使用它。他们认为很多编译器不支持它,代码容易产生多义性,调试起来困难,而且很多时候用多重继承做的事即使不使用它同样也可以做到。
  • 至于什么时候用单一继承,什么时候用多重继承,我们只需要记住一点,那就是:在用单一继承就可以实现的情况下,不要使用多重继承