子类继承基类,基类派生子类,子类对象“is a”基类对象
继承语法:
xxxxxxxxxx
31class 子类 : 继承方式1 基类1, 继承方式2 基类2, ... {
2 ...
3};
继承方式:公有继承(public)、保护继承(protected)、私有继承(private)
xxxxxxxxxx
971// human.cpp
2
3// 继承的概念和语法
4
5
6
7using namespace std;
8/*
9class Student {
10public:
11 Student(const char* name, int age, int num)
12 : name(name), age(age), num(num) {}
13
14 void who(void) const {
15 cout << "我是" << name << ",今年" << age << "岁。" << endl;
16 }
17
18 void learn(const char* course) const {
19 cout << "我在学" << course << ",我的学号是" << num << "。" << endl;
20 }
21
22private:
23 string name;
24 int age;
25 int num;
26};
27
28class Teacher {
29public:
30 Teacher(const char* name, int age, const char* job)
31 : name(name), age(age), job(job) {}
32
33 void who(void) const {
34 cout << "我是" << name << ",今年" << age << "岁。" << endl;
35 }
36
37 void teach(const char* course) const {
38 cout << "我在教" << course << ",我的职位是" << job << "。" << endl;
39 }
40
41private:
42 string name;
43 int age;
44 string job;
45};
46*/
47class Human {
48public:
49 Human(const char* name, int age)
50 : name(name), age(age) {}
51
52 void who(void) const {
53 cout << "我是" << name << ",今年" << age << "岁。" << endl;
54 }
55
56private:
57 string name;
58 int age;
59};
60
61class Student : public Human {
62public:
63 Student(const char* name, int age, int num)
64 : Human(name, age), num(num) {}
65
66 void learn(const char* course) const {
67 cout << "我在学" << course << ",我的学号是" << num << "。" << endl;
68 }
69
70private:
71 int num;
72};
73
74class Teacher : public Human {
75public:
76 Teacher(const char* name, int age, const char* job)
77 : Human(name, age), job(job) {}
78
79 void teach(const char* course) const {
80 cout << "我在教" << course << ",我的职位是" << job << "。" << endl;
81 }
82
83private:
84 string job;
85};
86
87int main(void) {
88 Student student("李明", 25, 1001);
89 student.who();
90 student.learn("英语");
91
92 Teacher teacher("陈飞", 48, "教授");
93 teacher.who();
94 teacher.teach("数学");
95
96 return 0;
97}
一个子类类型的对象在任何时候都可以作为一个基类类型的对象,而不必使用显示的类型转换,前提是两者(子类及其基类)都是通过指针或引用操作的
xxxxxxxxxx
251class User {
2public:
3 User(...) {
4 ...
5 }
6
7private:
8 char* name;
9 int age;
10};
11
12class StudentUser : public User {
13public:
14 StudentUser(...) {
15 ...
16 }
17
18private:
19 char** listOfCourses;
20 int numbOfCourses;
21 int whatYear;
22};
23
24StudentUser* studentUser = new StudentUser(...);
25User* user = studentUser; // 安全的向上造型
反之,任何时候都无法将一个基类类型的指针或引用,隐式转换为子类类型的指针或引用
xxxxxxxxxx
21User* user = new User(...);
2StudentUser* studentUser = user; // 编译错误
使用静态造型(强制类型转换)固然可以规避语法上限制,但并不安全
xxxxxxxxxx
11StudentUser* studentUser = static_cast<StudentUser*>(user); // 不安全的向下造型
向下造型的安全性,取决于代码编写者能否确知,该基类指针或引用的目标对象真的是一个子类对象
xxxxxxxxxx
21User* user = new StudentUser(...);
2StudentUser* studentUser = static_cast<StudentUser*>(user); // 安全的向下造型
在子类中可以直接使用基类的所有公有和保护成员,就象它们是在子类中声明的那样,但基类的私有成员在子类对象中虽然存在却不可见,故无法直接使用
基类的公有和保护成员在子类中不仅可见,而且可被重新定义
由此产生的名字冲突可以通过“子类中的名字定义隐藏所有基类中的同名定义”规则而避免
借助作用域分解操作符(::),可通过子类或在其中,访问那些在基类中定义却被子类所隐藏的名字
访控限定符 | 访控属性 | 自己 | 子类 | 外部 | 友元 |
---|---|---|---|---|---|
public | 公有成员 | Yes | Yes | Yes | Yes |
protected | 保护成员 | Yes | Yes | No | Yes |
private | 私有成员 | Yes | No | No | Yes |
xxxxxxxxxx
561// accctrl.cpp
2
3// 类成员的访问控制
4
5class A {
6public:
7 void pub_fun(void) {}
8 char pub_var;
9
10protected:
11 void pro_fun(void) {}
12 char pro_var;
13
14private:
15 void pri_fun(void) {}
16 char pri_var;
17
18 void foo(void) {
19 pub_fun();
20 pub_var = 10;
21
22 pro_fun();
23 pro_var = 10;
24
25 pri_fun();
26 pri_var = 10;
27 }
28};
29
30class B : public A {
31 void foo(void) {
32 pub_fun();
33 pub_var = 10;
34
35 pro_fun();
36 pro_var = 10;
37
38 // pri_fun(); // 编译错误
39 // pri_var = 10; // 编译错误
40 }
41};
42
43int main(void) {
44 A a;
45
46 a.pub_fun();
47 a.pub_var = 10;
48
49 // a.pro_fun();
50 // a.pro_var = 10;
51
52 // a.pri_fun(); // 编译错误
53 // a.pri_var = 10; // 编译错误
54
55 return 0;
56}
基类中的 | 在公有子类中变成 | 在保护子类中变成 | 在私有子类中变成 |
---|---|---|---|
公有成员 | 公有成员 | 保护成员 | 私有成员 |
保护成员 | 保护成员 | 保护成员 | 私有成员 |
私有成员 | 私有成员 | 私有成员 | 私有成员 |
xxxxxxxxxx
501// public.cpp
2
3// 基类成员的访控属性在公有子类中的变化规则:公保私->公保私
4
5class A {
6public:
7 void pub_fun(void) {}
8 char pub_var;
9
10protected:
11 void pro_fun(void) {}
12 char pro_var;
13
14private:
15 void pri_fun(void) {}
16 char pri_var;
17};
18
19class B : public A {};
20
21class C : public B {
22 void foo(void) {
23 pub_fun();
24 pub_var = 10;
25
26 pro_fun();
27 pro_var = 10;
28
29 // pri_fun(); // 编译错误
30 // pri_var = 10; // 编译错误
31 }
32};
33
34int main(void) {
35 B b;
36
37 b.pub_fun();
38 b.pub_var = 10;
39
40 // b.pro_fun(); // 编译错误
41 // b.pro_var = 10; // 编译错误
42
43 // b.pri_fun(); // 编译错误
44 // b.pri_var = 10; // 编译错误
45
46 A* pa = &b;
47 A& ra = b;
48
49 return 0;
50}
xxxxxxxxxx
591// protected.cpp
2
3// 基类成员的访控属性在保护子类中的变化规则:公保私->保保私
4
5class A {
6public:
7 void pub_fun(void) {}
8 char pub_var;
9
10protected:
11 void pro_fun(void) {}
12 char pro_var;
13
14private:
15 void pri_fun(void) {}
16 char pri_var;
17};
18
19class B : protected A {};
20
21class C : public B {
22 void foo(void) {
23 pub_fun();
24 pub_var = 10;
25
26 pro_fun();
27 pro_var = 10;
28
29 // pri_fun(); // 编译错误
30 // pri_var = 10; // 编译错误
31 }
32};
33
34int main(void) {
35 B b;
36
37 // b.pub_fun(); // 编译错误
38 // b.pub_var = 10; // 编译错误
39
40 // b.pro_fun(); // 编译错误
41 // b.pro_var = 10; // 编译错误
42
43 // b.pri_fun(); // 编译错误
44 // b.pri_var = 10; // 编译错误
45
46 // A* p1 = &b; // 编译错误
47 // A* p2 = static_cast<A*>(&b); // 编译错误
48 // A* p3 = dynamic_cast<A*>(&b); // 编译错误
49 A* p4 = reinterpret_cast<A*>(&b);
50 A* p5 = (A*)&b;
51
52 // A& r1 = b; // 编译错误
53 // A& r2 = static_cast<A&>(b); // 编译错误
54 // A& r3 = dynamic_cast<A&>(b); // 编译错误
55 A& r4 = reinterpret_cast<A&>(b);
56 A& r5 = (A&)b;
57
58 return 0;
59}
xxxxxxxxxx
591// private.cpp
2
3// 基类成员的访控属性在私有子类中的变化规则:公保私->私私私
4
5class A {
6public:
7 void pub_fun(void) {}
8 char pub_var;
9
10protected:
11 void pro_fun(void) {}
12 char pro_var;
13
14private:
15 void pri_fun(void) {}
16 char pri_var;
17};
18
19class B : private A {};
20
21class C : public B {
22 void foo(void) {
23 // pub_fun(); // 编译错误
24 // pub_var = 10; // 编译错误
25
26 // pro_fun(); // 编译错误
27 // pro_var = 10; // 编译错误
28
29 // pri_fun(); // 编译错误
30 // pri_var = 10; // 编译错误
31 }
32};
33
34int main(void) {
35 B b;
36
37 // b.pub_fun(); // 编译错误
38 // b.pub_var = 10; // 编译错误
39
40 // b.pro_fun(); // 编译错误
41 // b.pro_var = 10; // 编译错误
42
43 // b.pri_fun(); // 编译错误
44 // b.pri_var = 10; // 编译错误
45
46 // A* p1 = &b; // 编译错误
47 // A* p2 = static_cast<A*>(&b); // 编译错误
48 // A* p3 = dynamic_cast<A*>(&b); // 编译错误
49 A* p4 = reinterpret_cast<A*>(&b);
50 A* p5 = (A*)&b;
51
52 // A& r1 = b; // 编译错误
53 // A& r2 = static_cast<A&>(b); // 编译错误
54 // A& r3 = dynamic_cast<A&>(b); // 编译错误
55 A& r4 = reinterpret_cast<A&>(b);
56 A& r5 = (A&)b;
57
58 return 0;
59}
子类隐式调用基类构造函数
xxxxxxxxxx
481// impbase.cpp
2
3// 子类隐式调用基类构造函数
4
5
6
7using namespace std;
8
9class User {
10public:
11 User(void) : name("Anonymous"), age(-1) {}
12
13 User(const char* name, int age) : name(name), age(age) {}
14
15private:
16 string name;
17 int age;
18
19 friend ostream& operator<<(ostream& os, const User& user) {
20 return os << user.name << ", " << user.age;
21 }
22};
23
24class StudentUser : public User {
25public:
26 // 如果子类的构造函数没有显式调用基类的构造函数,那么系统
27 // 将会调用基类的缺省构造函数。但是请注意,只有在为基类显
28 // 式提供一个缺省构造函数,或者不提供任何构造函数(系统会
29 // 提供一个缺省构造函数)的情况下,基类才拥有缺省构造函数
30
31 StudentUser(const char* name, int age, const char* school)
32 : school(school) {}
33
34private:
35 string school;
36
37 friend ostream& operator<<(ostream& os, const StudentUser& su) {
38 return os << static_cast<const User&>(su) << ", " << su.school;
39 }
40};
41
42int main(void) {
43 StudentUser su("Maura", 20, "Tarena");
44
45 cout << su << endl;
46
47 return 0;
48}
子类显式调用基类构造函数
xxxxxxxxxx
461// expbase.cpp
2
3// 子类显式调用基类构造函数
4
5
6
7using namespace std;
8
9class User {
10public:
11 User(void) : name("Anonymous"), age(-1) {}
12
13 User(const char* name, int age) : name(name), age(age) {}
14
15private:
16 string name;
17 int age;
18
19 friend ostream& operator<<(ostream& os, const User& user) {
20 return os << user.name << ", " << user.age;
21 }
22};
23
24class StudentUser : public User {
25public:
26 // 每个子类对象中都包含一个基类类型的子对象,即子类
27 // 对象的基类部分。该子对象是由基类的构造函数初始化
28
29 StudentUser(const char* name, int age, const char* school)
30 : User(name, age), school(school) {}
31
32private:
33 string school;
34
35 friend ostream& operator<<(ostream& os, const StudentUser& su) {
36 return os << static_cast<const User&>(su) << ", " << su.school;
37 }
38};
39
40int main(void) {
41 StudentUser su("Maura", 20, "Tarena");
42
43 cout << su << endl;
44
45 return 0;
46}
继承链的构造和析构顺序
xxxxxxxxxx
461// consorder.cpp
2
3// 继承链的构造和析构顺序
4
5
6
7using namespace std;
8
9class A {
10public:
11 A(void) {
12 cout << "A::A() invoked" << endl;
13 }
14
15 ~A(void) {
16 cout << "A::~A() invoked" << endl;
17 }
18};
19
20class B : public A {
21public:
22 B(void) {
23 cout << "B::B() invoked" << endl;
24 }
25
26 ~B(void) {
27 cout << "B::~B() invoked" << endl;
28 }
29};
30
31class C : public B {
32public:
33 C(void) {
34 cout << "C::C() invoked" << endl;
35 }
36
37 ~C(void) {
38 cout << "C::~C() invoked" << endl;
39 }
40};
41
42int main(void) {
43 C c;
44
45 return 0;
46}
基类分配资源,基类提供析构,子类未分配资源,子类无需提供析构
xxxxxxxxxx
471// defdes.cpp
2
3// 基类分配资源,基类提供析构,子类未分配资源,子类无需提供析构
4
5
6
7using namespace std;
8
9class X {
10public:
11 X(const int* data, size_t size)
12 : data(new int[size]), size(size) {
13 cout << "X::X() invoked" << endl;
14
15 for (int i = 0; i < this->size; ++i)
16 this->data[i] = data[i];
17 }
18
19 ~X(void) {
20 cout << "X::~X() invoked" << endl;
21
22 delete[] data;
23 }
24
25private:
26 int *data;
27 size_t size;
28};
29
30class Y : public X {
31public:
32 Y(const int* data, size_t size) : X(data, size) {
33 cout << "Y::Y() invoked" << endl;
34 }
35
36 // 子类既没有分配资源也没有提供析构函数。对于子类,系
37 // 统所提供的缺省析构函数完全可以满足要求,它会自动调
38 // 用基类的析构函数,而后者负责释放在基类中分配的资源
39};
40
41int main(void) {
42 int data[1024] = {};
43
44 Y y(data, sizeof(data) / sizeof(data[0]));
45
46 return 0;
47}
基类分配资源,基类提供析构,子类亦分配资源,子类必须提供析构
xxxxxxxxxx
591// mustdes.cpp
2
3// 基类分配资源,基类提供析构,子类亦分配资源,子类必须提供析构
4
5
6
7
8
9using namespace std;
10
11class X {
12public:
13 X(const int* data, size_t size)
14 : data(new int[size]), size(size) {
15 cout << "X::X() invoked" << endl;
16
17 for (int i = 0; i < this->size; ++i)
18 this->data[i] = data[i];
19 }
20
21 ~X(void) {
22 cout << "X::~X() invoked" << endl;
23
24 delete[] data;
25 }
26
27private:
28 int *data;
29 size_t size;
30};
31
32class Y : public X {
33public:
34 Y(const int* data, size_t size, const char* text)
35 : X(data, size), text(strcpy(new char[strlen(text)+1], text)) {
36 cout << "Y::Y() invoked" << endl;
37 }
38
39 // 如果没有为子类提供自定义的析构函数,那么系统为该子类提供的
40 // 缺省析构函数将在适当的时候被调用。该析构函数固然会调用基类
41 // 的析构函数,但它并不会释放子类动态分配的资源,导致内存泄漏
42
43 ~Y(void) {
44 cout << "Y::~Y() invoked" << endl;
45
46 delete[] text;
47 }
48
49private:
50 char* text;
51};
52
53int main(void) {
54 int data[1024] = {};
55
56 Y y(data, sizeof(data) / sizeof(data[0]), "hello world");
57
58 return 0;
59}
通过基类指针析构子类对象的问题
xxxxxxxxxx
601// delbd.cpp
2
3// 通过基类指针析构子类对象的问题
4
5
6
7
8
9using namespace std;
10
11class X {
12public:
13 X(const int* data, size_t size)
14 : data(new int[size]), size(size) {
15 cout << "X::X() invoked" << endl;
16
17 for (int i = 0; i < this->size; ++i)
18 this->data[i] = data[i];
19 }
20
21 ~X(void) {
22 cout << "X::~X() invoked" << endl;
23
24 delete[] data;
25 }
26
27private:
28 int *data;
29 size_t size;
30};
31
32class Y : public X {
33public:
34 Y(const int* data, size_t size, const char* text)
35 : X(data, size), text(strcpy(new char[strlen(text)+1], text)) {
36 cout << "Y::Y() invoked" << endl;
37 }
38
39 ~Y(void) {
40 cout << "Y::~Y() invoked" << endl;
41
42 delete[] text;
43 }
44
45private:
46 char* text;
47};
48
49int main(void) {
50 int data[1024] = {};
51
52 X* x = new Y(data, sizeof(data) / sizeof(data[0]), "hello world");
53
54 // delete一个指向子类对象的基类指针,只有基类的析构函数会被执行,
55 // 因为没有调用子类的析构函数,子类动态分配的资源将形成内存泄漏
56
57 delete x;
58
59 return 0;
60}
xxxxxxxxxx
901// copy.cpp
2
3// 子类的拷贝构造函数和拷贝赋值操作符函数
4
5
6
7using namespace std;
8
9class User {
10public:
11 User(void) : name("Anonymous"), age(-1) {}
12
13 User(const char* name, int age) : name(name), age(age) {}
14
15 // 拷贝构造函数
16 User(const User& user) : name(user.name), age(user.age) {}
17
18 // 拷贝赋值操作符函数
19 User& operator=(const User& user) {
20 if (&user != this) {
21 name = user.name;
22 age = user.age;
23 }
24
25 return *this;
26 }
27
28private:
29 string name;
30 int age;
31
32 friend ostream& operator<<(ostream& os, const User& user) {
33 return os << user.name << ", " << user.age;
34 }
35};
36
37class StudentUser : public User {
38public:
39 StudentUser(const char* name, int age, const char* school)
40 : User(name, age), school(school) {}
41
42 // 子类的拷贝构造函数必须显式调用基类的拷贝构造函数。如果基类没
43 // 有显式定义拷贝构造函数,那么系统会调用基类的缺省拷贝构造函数。
44 // 如果子类的拷贝构造函数没有显式调用基类的任何构造函数,那么系
45 // 统将试图调用基类的缺省构造函数,初始化子类对象中的基类子对象
46
47 // 拷贝构造函数
48 StudentUser(const StudentUser& su)
49 : User(su), school(su.school) {}
50
51 // 子类的拷贝赋值操作符函数必须显式调用基类的拷贝赋值操作符函数。
52 // 如果基类没有显式定义拷贝赋值操作符函数,那么系统会以默认方式
53 // 复制子类对象中的基类子对象。如果子类的拷贝赋值操作符函数没有
54 // 显式调用基类的拷贝赋值操作符函数,那么子类对象中的基类子对象
55 // 将不会被复制
56
57 // 拷贝赋值操作符函数
58 StudentUser& operator=(const StudentUser& su) {
59 if (&su != this) {
60 // User::operator=(su);
61 static_cast<User&>(*this) = su;
62 school = su.school;
63 }
64
65 return *this;
66 }
67
68private:
69 string school;
70
71 friend ostream& operator<<(ostream& os, const StudentUser& su) {
72 return os << static_cast<const User&>(su) << ", " << su.school;
73 }
74};
75
76int main(void) {
77 StudentUser su1 ("Maura", 20, "Tarena");
78 cout << su1 << endl;
79
80 StudentUser su2 = su1; // 拷贝构造
81 cout << su2 << endl;
82
83 StudentUser su3("Betty", 22, "MIT");
84 cout << su3 << endl;
85
86 su3 = su1; // 拷贝赋值
87 cout << su3 << endl;
88
89 return 0;
90}
xxxxxxxxxx
601// operator.cpp
2
3// 子类的其它操作符函数
4
5
6
7using namespace std;
8
9class Person {
10public:
11 Person(const char* name, int age) : name(name), age(age) {}
12
13private:
14 string name;
15 int age;
16
17 friend ostream& operator<<(ostream& os, const Person& person) {
18 return os << person.name << ", " << person.age;
19 }
20};
21
22class Employee : public Person {
23public:
24 Employee(const char* name, int age, const char* dept, double salary)
25 : Person(name, age), dept(dept), salary(salary) {}
26
27private:
28 string dept;
29 double salary;
30
31 friend ostream& operator<<(ostream& os, const Employee& emp) {
32 // 通过将子类引用向上造型为基类引用,迫使针对基类的操作符重载函
33 // 数在针对子类的操作符重载函数中被调用,输出子类中的基类子对象
34 return os << static_cast<const Person&>(emp) << ", " <<
35 emp.dept << ", " << emp.salary;
36 }
37};
38
39class Manager : public Employee {
40public:
41 Manager(const char* name, int age, const char* dept, double salary, const char* title)
42 : Employee(name, age, dept, salary), title(title) {}
43
44private:
45 string title;
46
47 friend ostream& operator<<(ostream& os, const Manager& man) {
48 // 通过将子类引用向上造型为基类引用,迫使针对基类的操作符重载函
49 // 数在针对子类的操作符重载函数中被调用,输出子类中的基类子对象
50 return os << static_cast<const Employee&>(man) << ", " << man.title;
51 }
52};
53
54int main(void) {
55 Manager man("Zaphod", 56, "Assembly", 5000.36, "Director");
56
57 cout << man << endl;
58
59 return 0;
60}
xxxxxxxxxx
701// genhide.cpp
2
3// 普通成员的名字隐藏
4
5
6
7using namespace std;
8
9class A {
10public:
11 A(void) : n(100) {}
12
13 void foo(void) const {
14 cout << "A::foo() invoked" << endl;
15 }
16
17 int n;
18};
19
20class B : public A {
21public:
22 B(void) : n(200) {}
23
24 void foo(int) const {
25 cout << "B::foo() invoked" << endl;
26 }
27
28 void bar(void) {
29 // foo(); // 编译错误,自己的foo隐藏了基类的foo,参数不匹配
30 foo(0); // 调用自己的foo
31 A::foo(); // 调用基类的foo
32
33 n = 300; // 访问自己的n
34 A::n = 400; // 访问基类的n
35 }
36
37 int n;
38};
39
40class C : public B {
41public:
42 using A::foo;
43 using B::foo;
44
45 void foo(int, int) const {
46 cout << "C::foo() invoked" << endl;
47 }
48};
49
50int main(void) {
51 B b;
52
53 b.bar();
54 cout << b.n << ", " << b.A::n << endl;
55
56 // b.foo(); // 编译错误,B的foo隐藏了A的foo,参数不匹配
57 b.foo(0); // 调用B的foo
58 b.A::foo(); // 调用A的foo
59
60 b.n++; // 访问B的n
61 b.A::n++; // 访问A的n
62 cout << b.n << ", " << b.A::n << endl;
63
64 C c;
65 c.foo(); // 重载匹配到A的foo
66 c.foo(0); // 重载匹配到B的foo
67 c.foo(0, 0); // 重载匹配到C的foo
68
69 return 0;
70}
xxxxxxxxxx
671// statichide.cpp
2
3// 静态成员的名字隐藏
4
5
6
7using namespace std;
8
9class A {
10public:
11 static void foo(void) {
12 cout << "A::foo() invoked" << endl;
13 }
14
15 static int n;
16};
17
18int A::n = 100;
19
20class B : public A {
21public:
22 static void foo(int) {
23 cout << "B::foo() invoked" << endl;
24 }
25
26 static void bar (void) {
27 // foo(); // 编译错误,自己的foo隐藏了基类的foo,参数不匹配
28 foo(0); // 调用自己的foo
29 A::foo(); // 调用基类的foo
30
31 n = 300; // 访问自己的n
32 A::n = 400; // 访问基类的n
33 }
34
35 static int n;
36};
37
38int B::n = 200;
39
40class C : public B {
41public:
42 using A::foo;
43 using B::foo;
44
45 static void foo(int, int) {
46 cout << "C::foo() invoked" << endl;
47 }
48};
49
50int main(void) {
51 B::bar();
52 cout << B::n << ", " << B::A::n << endl;
53
54 // B::foo (); // 编译错误,B的foo隐藏了A的foo,参数不匹配
55 B::foo(0); // 调用B的foo
56 B::A::foo(); // 调用A的foo
57
58 B::n++; // 访问B的n
59 B::A::n++; // 访问A的n
60 cout << B::n << ", " << B::A::n << endl;
61
62 C::foo(); // 重载匹配到A的foo
63 C::foo(0); // 重载匹配到B的foo
64 C::foo(0, 0); // 重载匹配到C的foo
65
66 return 0;
67}
不良的设计
xxxxxxxxxx
431// private1.cpp
2
3// 不良的设计
4
5
6
7using namespace std;
8
9class SalaryDB {
10public:
11 int querySalary(const string& name) const {
12 if (name == "关羽")
13 return 10000;
14
15 if (name == "刘备")
16 return 60000;
17
18 return 0;
19 }
20};
21
22// 公有继承导致SalaryDB类中的公有成员也成为Employee类的公有成员
23class Employee : public SalaryDB {
24public:
25 Employee(const string& name) : name(name) {}
26
27 bool fire(void) const {
28 return querySalary(name) > 20000;
29 }
30
31 string name;
32};
33
34int main(void) {
35 Employee emp("关羽");
36
37 cout << (emp.fire() ? "裁掉" : "留用") << emp.name << endl;
38
39 // 可以从外部获取本应仅限于被Employee类访问的内部信息
40 cout << emp.querySalary(emp.name) << endl;
41
42 return 0;
43}
改进的设计
xxxxxxxxxx
431// private2.cpp
2
3// 改进的设计
4
5
6
7using namespace std;
8
9class SalaryDB {
10public:
11 int querySalary(const string& name) const {
12 if (name == "关羽")
13 return 10000;
14
15 if (name == "刘备")
16 return 60000;
17
18 return 0;
19 }
20};
21
22// 私有继承保证了SalaryDB类中的公有成员在Employee类中变成私有
23class Employee : private SalaryDB {
24public:
25 Employee(const string& name) : name(name) {}
26
27 bool fire(void) const {
28 return querySalary(name) > 20000;
29 }
30
31 string name;
32};
33
34int main(void) {
35 Employee emp("关羽");
36
37 cout << (emp.fire() ? "裁掉" : "留用") << emp.name << endl;
38
39 // 无法从外部获取只能被Employee类访问的内部信息
40 // cout << emp.querySalary(emp.name) << endl; // 编译错误
41
42 return 0;
43}
可扩展的设计
xxxxxxxxxx
621// private3.cpp
2
3// 可扩展的设计
4
5
6
7using namespace std;
8
9class SalaryDB {
10public:
11 int querySalary(const string& name) const {
12 if (name == "关羽")
13 return 10000;
14
15 if (name == "刘备")
16 return 60000;
17
18 return 0;
19 }
20};
21
22// 保护继承在确保SalaryDB的公有成员无法从Employee类外
23// 部访问的同时,为其子类留有方便之门,以利于后续扩展
24class Employee : protected SalaryDB {
25public:
26 Employee(const string& name) : name(name) {}
27
28 bool fire(void) const {
29 return querySalary(name) > 20000;
30 }
31
32 string name;
33};
34
35class Manager : public Employee {
36public:
37 Manager(const string& name) : Employee(name) {}
38
39 bool fire(void) const {
40 // querySalary成员函数在Employee类中是保护的,
41 // 作为Employee类的子类,Manager类可以访问它
42 return querySalary(name) > 50000;
43 }
44};
45
46int main(void) {
47 Employee emp("关羽");
48
49 cout << (emp.fire() ? "裁掉" : "留用") << emp.name << endl;
50
51 // 无法从外部获取只能被Employee类及其子类访问的内部信息
52 // cout << emp.querySalary(emp.name) << endl; // 编译错误
53
54 Manager man("刘备");
55
56 cout << (man.fire() ? "裁掉" : "留用") << man.name << endl;
57
58 // 无法从外部获取只能被Employee类及其子类访问的内部信息
59 // cout << man.querySalary(man.name) << endl; // 编译错误
60
61 return 0;
62}
xxxxxxxxxx
611// miorder.cpp
2
3// 多重继承的构造与析构
4
5
6
7using namespace std;
8
9class X {
10public:
11 X(void) {
12 cout << "X::X() invoked, this=" << this << endl;
13 }
14
15 ~X(void) {
16 cout << "X::~X() invoked, this=" << this << endl;
17 }
18
19 int x;
20};
21
22class Y {
23public:
24 Y(void) {
25 cout << "Y::Y() invoked, this=" << this << endl;
26 }
27
28 ~Y(void) {
29 cout << "Y::~Y() invoked, this=" << this << endl;
30 }
31
32 int y;
33};
34
35class Z : public X, public Y {
36public:
37 Z(void) {
38 cout << "Z::Z() invoked, this=" << this << endl;
39 }
40
41 ~Z(void) {
42 cout << "Z::~Z() invoked, this=" << this << endl;
43 }
44
45 int z;
46};
47
48int main(void) {
49 Z z;
50 cout << sizeof(z) << endl;
51
52 X* px = &z;
53 Y* py = &z;
54 Z* pz = &z;
55 cout << px << ", " << py << ", " << pz << endl;
56
57 pz = (Z*)py;
58 cout << pz << endl;
59
60 return 0;
61}
xxxxxxxxxx
601// diamond.cpp
2
3// 多重继承的重复创建问题——钻石继承
4
5// 当一个子类沿多条不同的路径继承同一个基类时,这个
6// 子类的实例化对象中将包含多个该基类的实例化子对象
7
8
9
10using namespace std;
11
12class A {
13public:
14 A(int n) : n(n) {
15 cout << "A::A() invoked, this=" << this << endl;
16 }
17
18 int n;
19};
20
21class X : public A {
22public:
23 X(int n) : A(n) {
24 cout << "X::X() invoked, this=" << this << endl;
25 }
26
27 int get(void) const {
28 cout << &n << "->" << n << endl;
29 return n;
30 }
31};
32
33class Y : public A {
34public:
35 Y(int n) : A(n) {
36 cout << "Y::Y() invoked, this=" << this << endl;
37 }
38
39 void set(int n) {
40 this->n = n;
41 cout << n << "->" << &this->n << endl;
42 }
43};
44
45class Z : public X, public Y {
46public:
47 Z(int n) : X(n), Y(n) {
48 cout << "Z::Z() invoked, this=" << this << endl;
49 }
50};
51
52int main(void) {
53 Z z(100);
54 cout << sizeof(z) << endl;
55
56 z.set(200);
57 cout << z.get() << endl;
58
59 return 0;
60}
xxxxxxxxxx
661// diamond.cpp
2
3// 虚继承
4
5// 将公共基类声明为虚基类,可以解决公共基
6// 类子对象在间接子类对象中的重复创建问题
7
8
9
10using namespace std;
11
12class A {
13public:
14 A(int n) : n(n) {
15 cout << "A::A() invoked, this=" << this << endl;
16 }
17
18 int n;
19};
20
21// 通过虚继承使A成为X的虚基类
22class X : virtual public A {
23public:
24 X(int n) : A(n) {
25 cout << "X::X() invoked, this=" << this << endl;
26 }
27
28 int get(void) const {
29 cout << &n << "->" << n << endl;
30 return n;
31 }
32};
33
34// 通过虚继承使A成为Y的虚基类
35class Y : virtual public A {
36public:
37 Y(int n) : A(n) {
38 cout << "Y::Y() invoked, this=" << this << endl;
39 }
40
41 void set(int n) {
42 this->n = n;
43 cout << n << "->" << &this->n << endl;
44 }
45};
46
47class Z : public X, public Y {
48public:
49 // 一般情况下,子类的构造函数不能调用其间接基类的构造函数。
50 // 但是,一旦这个间接基类被声明为虚基类,它的所有子类(无
51 // 论直接还是间接的)都必须显式调用该虚基类的构造函数。否
52 // 则,系统将试图为每个子类对象调用该虚基类的缺省构造函数
53 Z(int n) : X(n), Y(n), A(n) {
54 cout << "Z::Z() invoked, this=" << this << endl;
55 }
56};
57
58int main(void) {
59 Z z(100);
60 cout << sizeof(z) << endl;
61
62 z.set(200);
63 cout << z.get() << endl;
64
65 return 0;
66}
xxxxxxxxxx
411// funcconf.cpp
2
3// 多重继承的函数冲突问题
4
5// 如果在共同派生同一个子类的两个基类中,含有名字完全相同的两个成员函
6// 数,而且这个子类又没有对该成员函数进行隐藏或者覆盖,那么任何试图在
7// 这个子类中,或者通过这个子类的实例化对象调用该成员函数的操作,都将
8// 在编译期间引发一个链接歧义错误
9
10
11
12using namespace std;
13
14class X {
15public:
16 void foo(void) {
17 cout << "X::foo() invoked" << endl;
18 }
19};
20
21class Y {
22public:
23 void foo(void) {
24 cout << "Y::foo() invoked" << endl;
25 }
26};
27
28class Z : public X, public Y {
29public:
30 void bar(void) {
31 // foo(); // 编译错误
32 }
33};
34
35int main(void) {
36 Z z;
37
38 // z.foo(); // 编译错误
39
40 return 0;
41}
xxxxxxxxxx
521// converge.cpp
2
3// 汇聚替代
4
5// 在存在名字冲突的汇聚子类中,为该函数提供定
6// 义,以隐藏或覆盖其从不同基类继承的同名函数
7
8
9
10using namespace std;
11
12class X {
13public:
14 void foo(void) {
15 cout << "X::foo() invoked" << endl;
16 }
17};
18
19class Y {
20public:
21 void foo(void) {
22 cout << "Y::foo() invoked" << endl;
23 }
24};
25
26class Z : public X, public Y {
27public:
28 // 对于多个基类中的同名成员函数,可以在汇聚子类中为其提供定义,
29 // 以隐藏或覆盖该成员函数在所有基类中的版本。而该成员函数在汇
30 // 聚子类中的定义很可能仅仅是根据某种条件,选择适当的基类,再
31 // 辅以“::”操作符,以调用该成员函数在特定基类中的版本。这样做
32 // 既避免了因名字冲突而导致的编译错误,同时又保护了基类的成果
33
34 void foo(void) {
35 cout << "Z::foo() invoked" << endl;
36
37 X::foo();
38 Y::foo();
39 }
40
41 void bar(void){
42 foo();
43 }
44};
45
46int main(void) {
47 Z z;
48
49 z.foo();
50
51 return 0;
52}
xxxxxxxxxx
451// varconf.cpp
2
3// 多重继承的变量冲突问题
4
5// 如果在共同派生同一个子类的两个基类中,含有变量名完全相同的两个数据
6// 成员,而且这两个数据成员在子类中都可见,那么任何试图在这个子类中,
7// 或者通过这个子类的实例化对象访问该数据成员的操作,都将在编译期间引
8// 发一个名字冲突错误
9
10
11
12using namespace std;
13
14class X {
15public:
16 X(int n) : n(n) {}
17
18 int n;
19};
20
21class Y {
22public:
23 Y(int n) : n(n) {}
24
25 int n;
26};
27
28class Z : public X, public Y {
29public:
30 Z(int n) : X(n), Y(n) {}
31
32 void print(void) const {
33 // cout << n << endl; // 编译错误
34 }
35};
36
37int main(void) {
38 Z z(100);
39 z.print();
40
41 // z.n = 200; // 编译错误
42 z.print();
43
44 return 0;
45}
xxxxxxxxxx
501// scope.cpp
2
3// 类名限定
4
5// 一个位于多条继承路径汇聚点的类,为其不同基类中具有相同变量名的数
6// 据成员提供自己的定义,固然可以解决由此而产生的名字冲突问题,但是
7// 这些数据成员在基类中所体现的价值丝毫不会被继承到子类中。这里不妨
8// 任由这种冲突的存在,而在对数据成员的访问上采取更加谨慎的态度
9
10
11
12using namespace std;
13
14class X {
15public:
16 X(int n) : n(n) {}
17
18 int n;
19};
20
21class Y {
22public:
23 Y(int n) : n(n) {}
24
25 int n;
26};
27
28class Z : public X, public Y {
29public:
30 // 在子类的构造函数中,为不同的基类构造函数传递不同的参数
31 Z(int n1, int n2) : X(n1), Y(n2) {}
32
33 void print(void) const {
34 // 对不同基类中的同名数据成员,通过类名加“::”操作符加以区分
35 cout << X::n << ", " << Y::n << endl;
36 }
37};
38
39int main (int argc, char* argv[])
40{
41 Z z(100, 200);
42 z.print();
43
44 // 对不同基类中的同名数据成员,通过类名加“::”操作符加以区分
45 z.X::n = 300;
46 z.Y::n = 400;
47 z.print();
48
49 return 0;
50}
xxxxxxxxxx
431// convcomp.cpp
2
3// 通用类型转换、静态类型转换和重解释类型转换在多继承问题上的差异
4
5
6
7using namespace std;
8
9class A {
10 int n[2];
11};
12
13class B {
14 int n;
15};
16
17class C : public A, public B {};
18
19int main(void) {
20 A* pa;
21 B* pb;
22 C* pc = new C;
23
24 // 通用类型转换可能(因编译器而异)做指针计算,
25 // pb比pa和pc向下偏移两个整型(n[2])
26 pa = (A*)pc;
27 pb = (B*)pc;
28 cout << pa << ", " << pb << ", " << pc << endl;
29
30 // 静态类型转换做指针计算,
31 // pb比pa和pc向下偏移两个整型(n[2])
32 pa = static_cast<A*>(pc);
33 pb = static_cast<B*>(pc);
34 cout << pa << ", " << pb << ", " << pc << endl;
35
36 // 重解释类型转换不做指针计算,
37 // pb、pa和pc的值完全一样
38 pa = reinterpret_cast<A*>(pc);
39 pb = reinterpret_cast<B*>(pc);
40 cout << pa << ", " << pb << ", " << pc << endl;
41
42 return 0;
43}