继承
1. 派生类的定义
在已有的类的基础上,添加新的成员进行扩充,构成新类的机制称为派生/继承。已有的类称为基类/父类,扩充形成的新类称为派生类/子类。派生类和基类是一种is a的关系。比如说,学生Student是一类人Person,老师Teacher也是一类人Person,研究生GraduateStudent是一类学生Student。
1 class Person {
2 private:
3 string name;
4 Date birth;
5 bool gender;
6 };
7 class Teacher : public Person
8 {
9 private:
10 int salary;
11 int level;
12 };
13
14 class Student : public Person
15 {
16 private:
17 string ID;
18 int department;
19 };
20 class GradStudent : public Student {
21 private:
22 Teacher *tutor;
23 };
成员函数实现
1 class Person {
2 string name;
3 Date birth;
4 bool gender;
5 public:
6 string get_name();
7 Date get_date();
8 bool get_gender();
9 };
10 class Teacher : public Person {
11 int salary;
12 int level;
13 public:
14 int get_salary();
15 int get_level();
16 };
17 class Student: public Person {
18 string ID;
19 int department;
20 public:
21 string get_id();
22 int get_department();
23 };
24 class GradStudent: public Student {
25 Teacher *tutor;
26 public:
27 Teacher *get_tutor();
28 };
派生类的访问权限
- private成员:只在本类中可以访问,在派生类中不可访问的成员。基类的私有成员被派生类继承,但是不能被派生类访问
- protected成员:在本类及派生类中能访问的成员。派生类可以访问继承的保护成员,但是不能访问一个基类对象的保护成员
使用using声明改变基类成员权限
派生类的成员名字如果与基类相同,将隐藏基类成员
1 class Person {
2 public:
3 void set(string name);
4 void set(bool gender);
5 };
6 class Student : public Person{
7 public:
8 void set(int department); // hide base member functions
9 };
10 void f(Student &s) {
11 s.set("12345");
12 s.set( true );
13 s.Person::set("12345"); //ok
14 s.Person::set(true); //ok
15 }
2. 派生类的构造和析构
创建派生类对象时,基类的构造函数会被自动调用。如果派生类没有构造函数,或者没有显示调用,那么基类中的默认构造函数会被自动调用。
1 class Person {
2 public:
3 Person(string aname = "", bool agender = false) {
4 name = aname; gender = agender;
5 }
6 private:
7 string name;
8 bool gender;
9 };
10 class Student : public Person {
11 private:
12 int department;
13 };
14 int main() {
15 Student d; // default constructor of Person is called
16 }
派生类可以定义自己的构造函数,用于初始化派生类扩展的部分
如果基类的构造函数需要参数,那么需要使用初始化列表为基类构造提供参数。
1 class Person {
2 public:
3 Person(string aname, bool agender) {
4 name = aname;
5 gender = agender;
6 }
7 private:
8 string name;
9 bool gender;
10 };
11 class Student : public Person {
12 public:
13 Student(string name, bool gender, int dep)
14 : department(dep) , Person ( name, gender )
15 {
16 }
17 private:
18 int department;
19 };
创建一个派生类对象时,必须显式或者隐式的调用基类的构造函数。在一个多层的继承结构里面,创建一个派生类对象时,所有的基类的构造函数都会被调用。
1 class Person {
2 public:
3 Person( ) { cout << "construct Person"; }
4 };
5 class Student : public Person {
6 public:
7 Student( ) { cout << "construct Student"; }
8 };
9 class GradStudent : public Student {
10 public:
11 GradStudent( ) { cout << "construct GradStudent"; }
12 };
13 int main( ) {
14 GradStudent gs;
15 }
派生类对象被销毁时,基类的析构函数会被自动调用。如果派生类和基类都有析构函数,那么他们都会被调用。
派生类构造和析构顺序
1 class Person {
2 public:
3 Person() { cout << "construct Person" << endl; }
4 ~Person() { cout << "destruct Person" <<endl; }
5 };
6 class Student : public Person{
7 public:
8 Student() { cout << "construct Student" <<endl; }
9 ~Student() { cout << "destruct Student" <<endl; }
10 };
11 int main() {
12 Student s;
13 }
派生类的构造析构实例。派生类析构函数只负责派生类增加部分的分配资源的析构。
1 class Base {
2 public:
3 Base() {
4 s = new char[3];
5 }
6 ~Base() {
7 delete[ ] s;
8 }
9 private:
10 char *s;
11 };
12 class Derived : public Base {
13 public:
14 Derived() {
15 sd = new char[5];
16 }
17 ~Derived () {
18 delete[ ] sd;
19 }
20 private:
21 char *sd;
22 };
23 int main() {
24 Base b;
25 Derived d;
26 }
3. 派生类对象和对象指针的复制
有继承关系的对象复制
1 Student s("jack", Date(1980, 8, 8), true, 970101, 10);
2 Person p = s; //slice
3 Student s = p; //error
4
5 Student *pD = new Student("jack", Date(1980, 8, 8), true, 970101, 10);
6 Person *pB = pD; //correct 基类指针指向派生类对象
7 Person *pB2 = new Student("jack", Date(1980, 8, 8), true, 970101, 10);
8 pB = new Teacher; //多态性在这里体现
9
指针类型的转换
4. 多继承
5. 虚基类
6. 保护继承和私有继承
7. 多态与虚函数
8. 纯虚函数和抽象类
9. 运行时类型信息
10. 面向对象设计方法