继承是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(32.5);
    ds.display();
    gs.addcourse(33.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(254);
    fun(c);
    Rectangle t(2412);
    fun(t);
    system("pause");
    return ;
}

    多肽类让类的设计者去考虑工作的细节,而且这个细节简单到在成员函数上加一个virtual关键字。多态性使用用程序代码极大的简化,它是开启继承能力的钥匙