c++详细学习——继承
阅读原文时间:2023年07月08日阅读:1

通常讲父类(parrent)-子类(child)、基类(base)-派生类(derived)和超类(super)-子类(sub)

1 最基础的写法

以下例子为最基本的写法,默认构造

1 enum Gender {
2 MALE,
3 FEMALE,
4 };
5
6 class Person
7 {
8 private:
9 string name;
10 Gender gend;
11 int age;
12 public:
13 Person():name(""), gend(Gender::MALE), age(18)
14 {
15 cout << "Person::Person()" << endl;
16 }
17 ~Person()
18 {
19 cout << "Person::~Person()" << endl;
20 }
21 };
22
23 class Student : public Person
24 {
25 private:
26 int studentId;
27 int score;
28 public:
29 Student():studentId(10000), score(100)
30 {
31 cout << "Student::Student()" << endl;
32 }
33 ~Student()
34 {
35 cout << "Student::~Student()" << endl;
36 }
37 };

测试:

1 void TestAccess()
2 {
3 Student stu;
4 }

从运行结果来看,声明一个Student的对象之后,依次执行的是:Person的构造函数 --> Student的构造函数 --> Student的析构函数 --> Person的析构函数

2 访问权限

父类的所有public成员变量和函数都可以被子类访问、操作

Example

例子中父类Person的成员变量int age放在public中,不提供操作函数,测试函数中申明子类Student的对象后直接对age进行写和读,编译运行ok

1 enum Gender {
2 MALE,
3 FEMALE,
4 };
5
6 class Person
7 {
8 private:
9 string name;
10 Gender gend;
11 public:
12 Person():name(""), gend(Gender::MALE), age(18)
13 {
14 cout << "Person::Person()" << endl;
15 }
16 ~Person()
17 {
18 cout << "Person::~Person()" << endl;
19 }
20
21 void SetName(const string name_)
22 {
23 name = name_;
24 }
25 string GetName() const
26 {
27 return name;
28 }
29
30 int age;
31
32 void SetGender(const Gender gend_)
33 {
34 gend = gend_;
35 }
36 Gender GetGender() const
37 {
38 return gend;
39 }
40 };
41
42 class Student : public Person
43 {
44 private:
45 int studentId;
46 int score;
47 public:
48 Student():studentId(10000), score(100)
49 {
50 cout << "Student::Student()" << endl;
51 }
52 ~Student()
53 {
54 cout << "Student::~Student()" << endl;
55 }
56
57 void SetStudentId(const int id)
58 {
59 studentId = id;
60 }
61 int GetStudentId() const
62 {
63 return studentId;
64 }
65
66 void SetScore(const int score_)
67 {
68 score = score_;
69 }
70 int GetScore() const
71 {
72 return score;
73 }
74 };

测试函数:

1 void TestAccess()
2 {
3 Student stu;
4 stu.SetName("Tom");
5 stu.SetGender(Gender::FEMALE);
6 stu.age = 20; /* 直接操作成员变量 */
7 stu.SetStudentId(10001);
8 stu.SetScore(88);
9
10 cout << "name\t" << "gender\t" << "age\t" << "syudent ID\t" << "score" << endl;
11 cout << stu.GetName() << "\t" << stu.GetGender() << "\t" << stu.age << "\t"
12 << stu.GetStudentId() << "\t\t" << stu.GetScore() << endl;
13 }

运行结果ok:

子类拥有父类的所有private成员变量,可以通过public中父类提供的操作函数进行访问,但是没有直接操作和访问权限

Example

例子中父类Person的private成员变量int age,不提供操作函数,测试函数中申明子类Student的对象后直接对age进行写和读,编译error

1 enum Gender {
2 MALE,
3 FEMALE,
4 };
5
6 class Person
7 {
8 private:
9 string name;
10 Gender gend;
11 int age;
12 public:
13 Person():name(""), gend(Gender::MALE), age(18)
14 {
15 cout << "Person::Person()" << endl;
16 }
17 ~Person()
18 {
19 cout << "Person::~Person()" << endl;
20 }
21
22 void SetName(const string name_)
23 {
24 name = name_;
25 }
26 string GetName() const
27 {
28 return name;
29 }
30
31 void SetGender(const Gender gend_)
32 {
33 gend = gend_;
34 }
35 Gender GetGender() const
36 {
37 return gend;
38 }
39 };
40
41 class Student : public Person
42 {
43 private:
44 int studentId;
45 int score;
46 public:
47 Student():studentId(10000), score(100)
48 {
49 cout << "Student::Student()" << endl;
50 }
51 ~Student()
52 {
53 cout << "Student::~Student()" << endl;
54 }
55
56 void SetStudentId(const int id)
57 {
58 studentId = id;
59 }
60 int GetStudentId() const
61 {
62 return studentId;
63 }
64
65 void SetScore(const int score_)
66 {
67 score = score_;
68 }
69 int GetScore() const
70 {
71 return score;
72 }
73 };

测试函数:

1 void TestAccess()
2 {
3 Student stu;
4 stu.SetName("Tom");
5 stu.SetGender(Gender::FEMALE);
6 stu.age = 20; /* 直接操作成员变量 */
7 stu.SetStudentId(10001);
8 stu.SetScore(88);
9
10 cout << "name\t" << "gender\t" << "age\t" << "syudent ID\t" << "score" << endl;
11 cout << stu.GetName() << "\t" << stu.GetGender() << "\t" << stu.age << "\t"
12 << stu.GetStudentId() << "\t\t" << stu.GetScore() << endl;
13 }

编译结果error

父类protected成员变量和函数,子类可以当父类的private变量使用,但父类的对象不能不能使用

Example

例子中父类Person的protected成员函数PrintBaseInfo(),测试函数中Person的对象直接使用,编译error。但子类Student可以把它当父类的private成员函数一样使用。

1 enum Gender {
2 MALE,
3 FEMALE,
4 };
5
6 class Person
7 {
8 private:
9 string name;
10 Gender gend;
11 int age;
12 protected:
13 void PrintBaseInfo()
14 {
15 cout << "Person::PrintBaseInfo()\t";
16 cout << "name: " << name << "\tgend: " << gend << "\tage: " << age << endl;
17 }
18 public:
19 Person():name(""), gend(Gender::MALE), age(18)
20 {
21 cout << "Person::Person()" << endl;
22 }
23 ~Person()
24 {
25 cout << "Person::~Person()" << endl;
26 }
27
28 void SetName(const string name_)
29 {
30 name = name_;
31 }
32 string GetName() const
33 {
34 return name;
35 }
36
37 void SetGender(const Gender gend_)
38 {
39 gend = gend_;
40 }
41 Gender GetGender() const
42 {
43 return gend;
44 }
45
46 void SetAge(const int age_)
47 {
48 age = age_;
49 }
50 int GetAge() const
51 {
52 return age;
53 }
54 };
55
56 class Student : public Person
57 {
58 private:
59 int studentId;
60 int score;
61 public:
62 Student():studentId(10000), score(100)
63 {
64 cout << "Student::Student()" << endl;
65 }
66 ~Student()
67 {
68 cout << "Student::~Student()" << endl;
69 }
70
71 void SetStudentId(const int id)
72 {
73 studentId = id;
74 }
75 int GetStudentId() const
76 {
77 return studentId;
78 }
79
80 void SetScore(const int score_)
81 {
82 score = score_;
83 }
84 int GetScore() const
85 {
86 return score;
87 }
88
89 void Print()
90 {
91 PrintBaseInfo(); /* 子类使用父类的protected成员函数, ok */
92 }
93 };

测试函数:

1 void TestAccess()
2 {
3 Person per;
4 // per.PrintBaseInfo(); /* error */
5
6 Student stu;
7 stu.SetName("Tom");
8 stu.SetGender(Gender::FEMALE);
9 stu.SetAge(24);
10 stu.SetStudentId(10001);
11 stu.SetScore(88);
12 stu.Print();
13
14 cout << "name\t" << "gender\t" << "age\t" << "syudent ID\t" << "score" << endl;
15 cout << stu.GetName() << "\t" << stu.GetGender() << "\t" << stu.GetAge() << "\t"
16 << stu.GetStudentId() << "\t\t" << stu.GetScore() << endl;
17 }

执行结果:

3 构造和析构

在第1章中已经介绍,依次执行的是:Person的构造函数 --> Student的构造函数 --> Student的析构函数 --> Person的析构函数

子类对父类的初始化必须放在子类构造函数的初始化列表中,这是初始化父类的唯一办法

1 enum Gender {
2 MALE,
3 FEMALE,
4 };
5
6 class Person
7 {
8 private:
9 string name;
10 Gender gend;
11 int age;
12 public:
13 Person(const string &_name, const Gender _gend, const int _age) : name(_name), gend(_gend), age(_age)
14 {
15 cout << "Person::Person()" << endl;
16 }
17 ~Person()
18 {
19 cout << "Person::~Person()" << endl;
20 }
21 };
22
23 class Student : public Person
24 {
25 private:
26 int studentId;
27 int score;
28 public:
29 Student(const int id, const int _score) : Person("", Gender::MALE, 18), studentId(id), score(_score)
30 {
31 cout << "Student::Student()" << endl;
32 }
33 ~Student()
34 {
35 cout << "Student::~Student()" << endl;
36 }
37 };

4 继承与重载

在类中有多个函数类型和函数名相同,但参数列表不同的成员函数时,各个同名的函数之间形成重载,调用时根据调用者的参数去匹配这些重载函数

Example

Person类中4个Print之间构成重载的关系,Person的对象调用时根据传的实参参数类型或个数不同,执行不同的Print()。

1 enum Gender {
2 MALE,
3 FEMALE,
4 };
5
6 class Person
7 {
8 private:
9 string name;
10 Gender gend;
11 int age;
12 public:
13 Person(const string &_name, const Gender _gend, const int _age) : name(_name), gend(_gend), age(_age)
14 {
15 cout << "Person::Person()" << endl;
16 }
17 ~Person()
18 {
19 cout << "Person::~Person()" << endl;
20 }
21
22 void Print()
23 {
24 cout << "Person::Print 1" << endl;
25 }
26 void Print(const int num)
27 {
28 cout << "Person::Print 2" << endl;
29 }
30 void Print(const string str)
31 {
32 cout << "Person::Print 3" << endl;
33 }
34 void Print(const int num1, const int num2)
35 {
36 cout << "Person::Print 4" << endl;
37 }
38 };

测试函数:

1 void TestAccess()
2 {
3 Person per("", Gender::MALE, 18);
4 per.Print();
5 per.Print(100);
6 per.Print("hello");
7 per.Print(100, 300);
8 }

测试结果:

(1)子类中没有与父类重载函数同名的成员函数

子类中没有与父类重载函数同名的成员函数时,子类依然可以根据传递的参数类型不同或个数不同,调用到父类不同的函数

Example

父类Person中4个Print()之间构成重载的关系,子类Student的对象调用Print()时,根据传的实参参数类型或个数不同,执行父类不同的Print()。

1 enum Gender {
2 MALE,
3 FEMALE,
4 };
5
6 class Person
7 {
8 private:
9 string name;
10 Gender gend;
11 int age;
12 public:
13 Person(const string &_name, const Gender _gend, const int _age) : name(_name), gend(_gend), age(_age)
14 {
15 cout << "Person::Person()" << endl;
16 }
17 ~Person()
18 {
19 cout << "Person::~Person()" << endl;
20 }
21
22 void Print()
23 {
24 cout << "Person::Print 1" << endl;
25 }
26 void Print(const int num)
27 {
28 cout << "Person::Print 2" << endl;
29 }
30 void Print(const string str)
31 {
32 cout << "Person::Print 3" << endl;
33 }
34 void Print(const int num1, const int num2)
35 {
36 cout << "Person::Print 4" << endl;
37 }
38 };
39
40 class Student : public Person
41 {
42 private:
43 int studentId;
44 int score;
45 public:
46 Student(const int id, const int _score) : Person("", Gender::MALE, 18), studentId(id), score(_score)
47 {
48 cout << "Student::Student()" << endl;
49 }
50 ~Student()
51 {
52 cout << "Student::~Student()" << endl;
53 }
54 };

测试函数:

1 void TestAccess()
2 {
3 Student stu(10001, 100);
4
5 stu.Print();
6 stu.Print(100);
7 stu.Print("hello");
8 stu.Print(100, 300);
9 }

测试结果:

(2)子类中存在与父类重载函数同名的成员函数

子类中存在与父类重载函数相同函数名的成员函数时,子类的该函数与父类的重载函数没有关系,此在OOP语言中是C++独有的,称之为名字隐藏(name hidden)

Example

子类中也有Print()函数,此时子类的Print()把父类的Print()隐藏掉了

1 enum Gender {
2 MALE,
3 FEMALE,
4 };
5
6 class Person
7 {
8 private:
9 string name;
10 Gender gend;
11 int age;
12 public:
13 Person(const string &_name, const Gender _gend, const int _age) : name(_name), gend(_gend), age(_age)
14 {
15 cout << "Person::Person()" << endl;
16 }
17 ~Person()
18 {
19 cout << "Person::~Person()" << endl;
20 }
21
22 void Print()
23 {
24 cout << "Person::Print 1" << endl;
25 }
26 void Print(const int num)
27 {
28 cout << "Person::Print 2" << endl;
29 }
30 void Print(const string str)
31 {
32 cout << "Person::Print 3" << endl;
33 }
34 void Print(const int num1, const int num2)
35 {
36 cout << "Person::Print 4" << endl;
37 }
38 };
39
40 class Student : public Person
41 {
42 private:
43 int studentId;
44 int score;
45 public:
46 Student(const int id, const int _score) : Person("", Gender::MALE, 18), studentId(id), score(_score)
47 {
48 cout << "Student::Student()" << endl;
49 }
50 ~Student()
51 {
52 cout << "Student::~Student()" << endl;
53 }
54
55 void Print()
56 {
57 cout << "Student::Print()" << endl;
58 }
59 };

测试函数:

1 void TestAccess()
2 {
3 Student stu(10001, 100);
4
5 stu.Print();
6 // stu.Print(100); /* 编译error */
7 // stu.Print("hello"); /* 编译error */
8 // stu.Print(100, 300); /* 编译error */
9 }

测试结果: