继承是C++语言的一种重要机制,该机制自动地为一个类提供来自另一个类的操作和数据结构,这使得程序员只需在新类中定义已有类中没有的成分来建立新类。理解继承是理解面向对象程序设计的所有方面的关键,所以本章是很重要的。
1、继承的概念:
鸭子是鸟类的派生,鸭子是鸟类的一种,鸭子又拥有自己的特征,就是会嘎嘎叫。嘎嘎叫是区别于其他鸟类的属性。
面向对象程序设计可以让你声明一个新类作为另一个类的派生。派生类(也称为子类继承他父类的属性和操作子类也声明了新的属性和操作,剔除了那些不适合与其用途的继承下来的操作。这样继承可让你重用父类的代码,专注于为子类写新代码。)这样使我们重新使用父类代码成为可能。
继承可以使已存在的类不需修改地适应新应用,理解继承是理解面向对象程序设计所有方面的关键。
2、继承的工作方式。
1
2
3
4
5
6
|
class student { } class gradutestudent: public student { } |
gruduatestudent类继承了student的所有成员。集成的方式是在类定义中类名后跟:public student。一个研究生是一个学生。当然研究生类也有自己特有的成员。
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
|
# include <iostream> # include <string> using namespace std; class Advisor //教授类 { public : Advisor(); ~Advisor(); private : int numofmeeting; }; Advisor::Advisor() { } Advisor::~Advisor() { } class Student { public : Student(char* pname); void addcourse( int hours, float score) { average = (semesterhours + average + score); //总分 semesterhours += hours; //总修学时 average /= semesterhours; //平均分 } int gethours() { return semesterhours; } float getaverage() { return average; } void display() { cout << "name:" << name << endl; cout << "semehours:" << semesterhours << endl; cout << "averages:" << average << endl; } ~Student(); private : char name[ 40 ]; int semesterhours; float average; }; Student::Student(char *pname= "no name" ) { strncpy(name, pname, sizeof(name)); average = semesterhours = 0 ; } Student::~Student() { } class GraduateStudent: public Student { public : GraduateStudent(); int getqualifier() { return qualifierGrade; } ~GraduateStudent(); private : Advisor advisor; int qualifierGrade; }; GraduateStudent::GraduateStudent() { } GraduateStudent::~GraduateStudent() { } void main() { Student ds( "lo see undergrade" ); GraduateStudent gs; ds.addcourse( 3 , 2.5 ); ds.display(); gs.addcourse( 3 , 3.0 ); gs.display(); system( "pause" ); return ; } |
子类的实例化对象可以做父类实例化对象能做的任何事情,拥有父类的数据成员,父类的成员函数。
3、派生类的构造:
根据类的实现机制,派生类对象创建时,将执行其默认的构造函数。该默认构造函数会首先调用基类的默认构造函数,而基类没有默认构造函数,但正好匹配默认参数的构造函数。所以在运行结果中,gs对象的name值为no name。
派生类可以直接访问基类的私有数据成员,甚至在构造时初始化他们,但是一般不这么做,而是通过基类的接口(成员函数)去访问他们,初始化也是通过基类的构造函数。
类与类之间你做你的,我做我的,以接口做沟通。即使基类与子类也不例外。这正是类能够发挥其生命力的原因所在。
在构造一个子类时,完成其基类部分的构造有积累的构造函数去做,C++类的继承机制满意的提供了这种支持。
4、继承与组合:
类以另一个类对象做数据成员,称为组合,继承与组合都发挥了重要作用,他们将以前设计好的类采用“拿来主义”,但是两者在使用上有所不同。graduatestudent是student类的一种,所以graduatestudent享有student的一切待遇。这种关系的差别,决定了操作上的差别。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class vehicle {}; class motor {}; class car: public vehicle { public : motor motor; }; void vehiclefn(vehicle& v) {}; void motorfn(motor &m); void main() { car c; vehiclefn(c); //ok motorfn(c); //error motorfn(c.motor); //ok } |
汽车是车辆的子类,他继承了车辆的所有特征,而汽车具有马达,如果拥有了一辆汽车,因为汽车包含有马达,所以,同时也拥有了一个马达。
5、多态性:
gaduatestudent类对象gs调用student类的成员函数display(),该函数在输出时,没办法输出graduatestudent自己的数据成员qualiciergrade。因此在使用继承时,希望重载display()。
C++允许子类重载基类的成员函数。
6、多态的思考方式:
若是语言不支持多态,则不能被称为面向对象的语言。
7、多态性如何工作:
为了指明某个成员函数具有多态性,用关键字virtual来标志其为虚函数。
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
|
# include <iostream> # include <string> using namespace std; class Base { public : Base(); virtual void fn() { cout << "in base class" << endl;; } ~Base(); private : }; Base::Base() { } Base::~Base() { } class Subclass: public Base { public : Subclass(); virtual void fn() { cout << "in subclass " << endl;; } ~Subclass(); private : }; Subclass::Subclass() { } Subclass::~Subclass() { } void test(Base & b) { b.fn(); } void main() { Base bc; Subclass sc; cout << "calling test (bc):" ; test(bc); cout << "calling test (sc):" ; test(sc); system( "pause" ); return ; } |
fn()是base类的虚函数,在test()函数中,b是基类base的传引用形参,base类对象和subclass类对象都可作为参数传递给b,所以b.fn()的调用要等到运行时,才能确认是调用基类的fn()还是子类的fn()。
由于fn()标志为虚函数,编译看见b.fn()后,将其作为迟后联编来实现。因为多态性增加了一些数据存储和执行指令的代价,所以能不多态最好。
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
|
# include <iostream> # include <string> using namespace std; class Shape { public : Shape(double x, double y) :xcoord(x), ycoord(y) { } virtual double Area() const { return 0.0 ; } ~Shape(); private : double xcoord; double ycoord; }; Shape::~Shape() { } class Circle: public Shape { public : Circle(double x, double y, double r) :Shape(x, y), radius(r) { } virtual double Area() const { return 3.14 *radius*radius; } ~Circle(); private : double radius; }; Circle::~Circle() { } class Rectangle: public Shape { public : Rectangle(double x1, double y1, double x2, double y2) :Shape(x1, y1), x2coord(x2), y2coord(y2){} double Rectangle::Area() const { return fabs((xcoord - x2coord)*(ycoord - y2coord)); } ~Rectangle (); private : double x2coord; double y2coord; }; Rectangle ::~Rectangle () { } void fun( const Shape & sp) { cout << sp.Area() << endl; } void main() { Circle c( 2 , 5 , 4 ); fun(c); Rectangle t( 2 , 4 , 1 , 2 ); fun(t); system( "pause" ); return ; } |
多肽类让类的设计者去考虑工作的细节,而且这个细节简单到在成员函数上加一个virtual关键字。多态性使用用程序代码极大的简化,它是开启继承能力的钥匙。