OOP,与其说是一种程序设计技巧,倒不如说是一种程序设计思想。这种思想来源于人类面对世间万物最朴素,最自然的感觉、想法和观点。只是直到OOP被做为一种程序设计方法被正式提出,这种人类与生俱来的智慧才真正影响到计算机程序设计的工业化进程
大型面向对象程序的基本思想就是把大型软件(常常由数以百万计的代码行组成)看成是一个由对象组成的社会
对象拥有足够的智能,能够理解从其它对象接收到的信息,并以适当的行为对此作出反应
对象能够从高层对象继承属性和行为,并允许低层对象从自己继承属性和行为
拥有相同属性和行为的对象被分成一组,形成一个特定的类
除了拥有一个以前所定义的类的所有属性和行为外,另外还有一些额外的、更加具体的属性和行为,那么它们便被认为是以前所定义的那个类的子类
OOP已成为几乎所有图形用户界面(GUI)编程的首选。OOP在这方面的能力是如此出众,以至于人们在那些并不直接支持OOP的语言(例如C)中也创建了一些模拟OOP的软件结构,以便进行GUI编程(例如GNOME/GTK+工具)
OOP在数据库和网络编程方面也逐渐展现出强大的威力
得益于数据抽象、代码重用等OOP所固有的特征,软件开发的效率获得极大地提升,成本大幅降低,进一步加速了计算机软件行业的工业化进程
OOP更适合于开发大型软件,相比于分而治之的结构化程序设计,OOP更加强调大处着眼的统一与整合,在软件工程领域发挥着无可替代的作用
除了掌握语法之外,必须精通每种语言中所蕴藏的,真正的OOP基石:封装、继承和多态
精通OOP的必由之路
精通一种“元”语言,例如UML(Unified Modeling Language,统一建模语言),它允许我们在概念层次上可视化地描述我们的设计方案
学习设计模式。在多年的实践中,人们已经总结出大量的设计模式,它们已经成为许多子问题的标准解决方案
xxxxxxxxxx
21class 类名 {
2};
例如:
xxxxxxxxxx
21class User {
2};
xxxxxxxxxx
31class 类名 {
2 类型 变量名;
3};
例如:
xxxxxxxxxx
61class User {
2 ...
3 string name;
4 int age;
5 ...
6};
xxxxxxxxxx
51class 类名 {
2 返回类型 函数名(形参表) {
3 函数体;
4 }
5};
例如:
xxxxxxxxxx
71class User {
2 ...
3 void print(void) {
4 cout << name << ", " << age << endl;
5 }
6 ...
7};
也可将声明与实现分开:
xxxxxxxxxx
31class 类名 {
2 返回类型 函数名(形参表);
3};
xxxxxxxxxx
31返回类型 类名::函数名(形参表) {
2 函数体;
3}
例如:
xxxxxxxxxx
51class User {
2 ...
3 void print(void);
4 ...
5};
xxxxxxxxxx
31void User::print(void) {
2 cout << name << ", " << age << endl;
3}
public:公有成员,谁都可以访问
private:私有成员,只有自己能访问
protected:保护成员,只有自己和子类可以访问
例如:
xxxxxxxxxx
101class User {
2public:
3 void print(void) {
4 cout << name << ", " << age << endl;
5 }
6
7private:
8 string name;
9 int age;
10};
访控限定符 | 访控属性 | 自己 | 子类 | 外部 |
---|---|---|---|---|
public | 公有成员 | Yes | Yes | Yes |
protected | 保护成员 | Yes | Yes | No |
private | 私有成员 | Yes | No | No |
注意:类的缺省访问控制属性为私有,而结构的缺省访问控制属性为公有。
xxxxxxxxxx
51class 类名 {
2 类名(形参表) {
3 函数体;
4 }
5};
例如:
xxxxxxxxxx
201class User {
2public:
3 User(void) {
4 name = "Anonymous";
5 age = -1;
6 }
7
8 User(string name, int age) {
9 this->name = name;
10 this->age = age;
11 }
12
13 void print(void) {
14 cout << name << ", " << age << endl;
15 }
16
17private:
18 string name;
19 int age;
20};
xxxxxxxxxx
21类名 对象名;
2类名 对象名(实参表);
例如:
xxxxxxxxxx
21User user;
2User user("Zaphod", 49);
另一种写法:
xxxxxxxxxx
21类名 对象名 = 类名();
2类名 对象名 = 类名(实参表);
例如:
xxxxxxxxxx
21User user = User();
2User user = User("Zaphod", 49);
xxxxxxxxxx
31类名 对象数组名[元素个数];
2类名 对象数组名[元素个数] = {类名(实参表), 类名(实参表), ...};
3类名 对象数组名[] = {类名(实参表), 类名(实参表), ...};
例如:
xxxxxxxxxx
31User users[3];
2User users[4] = {User("Zaphod", 49), User("Antony", 37), User("Stephen", 35)};
3User users[] = {User("Zaphod", 49), User("Antony", 37), User("Stephen", 35)};
xxxxxxxxxx
51类名* 对象指针 = new 类名;
2类名* 对象指针 = new 类名();
3类名* 对象指针 = new 类名(实参表);
4
5delete 对象指针;
例如:
xxxxxxxxxx
51User* user = new User;
2User* user = new User();
3User* user = new User("Zaphod", 49);
4
5delete user;
xxxxxxxxxx
51类名* 对象指针 = new 类名[元素个数];
2类名* 对象指针 = new 类名[元素个数] {类名(实参表), 类名(实参表), ...}; // >= C++11
3类名* 对象指针 = new 类名[] {类名(实参表), 类名(实参表), ...}; // >= C++11
4
5delete[] 对象指针;
例如:
xxxxxxxxxx
51User* users = new User[3];
2User* users = new User[4] {User("Zaphod", 49), User("Antony", 37), User("Stephen", 35)};
3User* users = new User[] {User("Zaphod", 49), User("Antony", 37), User("Stephen", 35)};
4
5delete[] users;
xxxxxxxxxx
1331// clsobj.cpp
2
3// 类的定义、声明、实现和实例化
4
5
6
7using namespace std;
8
9// 类的定义
10class User {
11public:
12 User(void) {
13 name = "Anonymous";
14 age = -1;
15 }
16
17 User(string name, int age) {
18 this->name = name;
19 this->age = age;
20 }
21
22 void print(void) {
23 cout << name << ", " << age << endl;
24 }
25
26private:
27 string name;
28 int age;
29};
30/*
31// 类的声明
32class User {
33public:
34 User(void);
35 User(string name, int age);
36 void print(void);
37
38private:
39 string name;
40 int age;
41};
42
43// 类的实现
44
45User::User(void) {
46 name = "Anonymous";
47 age = -1;
48}
49
50User::User(string name, int age) {
51 this->name = name;
52 this->age = age;
53}
54
55void User::print(void) {
56 cout << name << ", " << age << endl;
57}
58*/
59// 类的实例化
60int main(void) {
61 // 在栈中创建单个对象
62
63 User user1;
64 user1.print();
65
66 User user2("Zaphod", 49);
67 user2.print();
68
69 User user3 = User();
70 user3.print();
71
72 User user4 = User("Antony", 37);
73 user4.print();
74
75 // 在栈中创建对象数组
76
77 User users1[3];
78 for (int i = 0; i < 3; ++i)
79 users1[i].print();
80
81 User users2[4] = {
82 User("Zaphod", 49),
83 User("Antony", 37),
84 User("Stephen", 35)};
85 for (int i = 0; i < 4; ++i)
86 users2[i].print();
87
88 User users3[] = {
89 User("Zaphod", 49),
90 User("Antony", 37),
91 User("Stephen", 35)};
92 for (int i = 0; i < 3; ++i)
93 users3[i].print();
94
95 // 在堆中创建/销毁单个对象
96
97 User* user5 = new User;
98 user5->print();
99 delete user5;
100
101 User* user6 = new User();
102 user6->print();
103 delete user6;
104
105 User* user7 = new User("Zaphod", 49);
106 user7->print ();
107 delete user7;
108
109 // 在堆中创建/销毁对象数组
110
111 User* users4 = new User[3];
112 for (int i = 0; i < 3; ++i)
113 users4[i].print();
114 delete[] users4;
115
116 User* users5 = new User[4] {
117 User("Zaphod", 49),
118 User("Antony", 37),
119 User("Stephen", 35)};
120 for (int i = 0; i < 4; ++i)
121 users5[i].print();
122 delete[] users5;
123
124 User* users6 = new User[] {
125 User("Zaphod", 49),
126 User("Antony", 37),
127 User("Stephen", 35)};
128 for (int i = 0; i < 3; ++i)
129 users6[i].print();
130 delete[] users6;
131
132 return 0;
133}
xxxxxxxxxx
201// user.h
2
3// 声明User类
4
5
6
7
8
9using namespace std;
10
11class User {
12public:
13 User(void);
14 User(string name, int age);
15 void print(void);
16
17private:
18 string name;
19 int age;
20};
xxxxxxxxxx
231// user.cpp
2
3// 实现User类
4
5
6
7
8
9using namespace std;
10
11User::User(void) {
12 name = "Anonymous";
13 age = -1;
14}
15
16User::User(string name, int age) {
17 this->name = name;
18 this->age = age;
19}
20
21void User::print(void) {
22 cout << name << ", " << age << endl;
23}
xxxxxxxxxx
801// main.cpp
2
3// 使用User类
4
5
6
7int main(void) {
8 // 在栈中创建单个对象
9
10 User user1;
11 user1.print();
12
13 User user2("Zaphod", 49);
14 user2.print();
15
16 User user3 = User();
17 user3.print();
18
19 User user4 = User("Antony", 37);
20 user4.print();
21
22 // 在栈中创建对象数组
23
24 User users1[3];
25 for (int i = 0; i < 3; ++i)
26 users1[i].print();
27
28 User users2[4] = {
29 User("Zaphod", 49),
30 User("Antony", 37),
31 User("Stephen", 35)};
32 for (int i = 0; i < 4; ++i)
33 users2[i].print();
34
35 User users3[] = {
36 User("Zaphod", 49),
37 User("Antony", 37),
38 User("Stephen", 35)};
39 for (int i = 0; i < 3; ++i)
40 users3[i].print();
41
42 // 在堆中创建/销毁单个对象
43
44 User* user5 = new User;
45 user5->print();
46 delete user5;
47
48 User* user6 = new User();
49 user6->print();
50 delete user6;
51
52 User* user7 = new User("Zaphod", 49);
53 user7->print ();
54 delete user7;
55
56 // 在堆中创建/销毁对象数组
57
58 User* users4 = new User[3];
59 for (int i = 0; i < 3; ++i)
60 users4[i].print();
61 delete[] users4;
62
63 User* users5 = new User[4] {
64 User("Zaphod", 49),
65 User("Antony", 37),
66 User("Stephen", 35)};
67 for (int i = 0; i < 4; ++i)
68 users5[i].print();
69 delete[] users5;
70
71 User* users6 = new User[] {
72 User("Zaphod", 49),
73 User("Antony", 37),
74 User("Stephen", 35)};
75 for (int i = 0; i < 3; ++i)
76 users6[i].print();
77 delete[] users6;
78
79 return 0;
80}
xxxxxxxxxx
771// consover.cpp
2
3// 构造函数可以重载
4
5
6
7using namespace std;
8
9class User {
10public:
11 // 无参构造函数,又名缺省构造函数或默认构造函数
12 User(void) {}
13
14 User(string name) {
15 this->name = name;
16 }
17
18 User(int age) {
19 this->age = age;
20 }
21
22 User(string name, int age) {
23 this->name = name;
24 this->age = age;
25 }
26
27 void print(void) {
28 cout << name << ", " << age << endl;
29 }
30
31private:
32 string name;
33 int age;
34};
35
36int main(void) {
37 // 在栈中创建对象,未显式赋初值的基本类型成
38 // 员变量为随机数,类类型成员变量被缺省构造
39
40 // User user1(); // 编译错误,被误解为函数声明
41 User user1;
42 user1.print();
43
44 User user2("Stephen");
45 user2.print();
46
47 User user3(37);
48 user3.print();
49
50 User user4("Zaphod", 49);
51 user4.print();
52
53 // 在堆中创建对象,未显式赋初值的基本类型成
54 // 员变量为零值,类类型成员变量被缺省构造
55
56 User* user5 = new User();
57 user5->print();
58 delete user5;
59
60 User* user6 = new User;
61 user6->print();
62 delete user6;
63
64 User* user7 = new User("Stephen");
65 user7->print();
66 delete user7;
67
68 User* user8 = new User(37);
69 user8->print();
70 delete user8;
71
72 User* user9 = new User("Zaphod", 49);
73 user9->print();
74 delete user9;
75
76 return 0;
77}
缺省构造函数亦称无参构造函数,但其未必真的没有任何参数。为一个有参构造函数的每个参数都提供一个缺省值,同样可以达到无参构造函数的效果
xxxxxxxxxx
111class UserGroup {
2public:
3 UserGroup(User* users = NULL, int priority = 10) {
4 this->users = users;
5 this->priority = priority;
6 }
7
8private:
9 User* users;
10 int priority;
11};
对于没有定义任何构造函数的类,系统会为其提供一个缺省构造函数
xxxxxxxxxx
461// defcons.cpp
2
3// 若未定义构造函数,则系统会提供一个缺省构造函数
4
5
6
7using namespace std;
8
9class User {
10public:
11 // 未定义构造函数,系统提供缺省构造函数
12
13 void print(void) {
14 cout << name << ", " << age << endl;
15 }
16
17private:
18 string name;
19 int age;
20};
21
22int main(void) {
23 // 在栈中缺省构造单个对象或对象数组,基本类型成员变量
24 // 不做初始化,类类型成员变量被缺省构造
25
26 User user1;
27 user1.print();
28
29 User users1[3];
30 for (int i = 0; i < 3; ++i)
31 users1[i].print();
32
33 // 在堆中缺省构造单个对象或对象数组,基本类型成员变量
34 // 被初始化为适当类型的零值,类类型成员变量被缺省构造
35
36 User* user2 = new User;
37 user2->print();
38 delete user2;
39
40 User* users2 = new User[3];
41 for (int i = 0; i < 3; ++i)
42 users2[i].print();
43 delete[] users2;
44
45 return 0;
46}
在栈中缺省构造单个对象或对象数组,基本类型成员变量不做初始化,类类型成员变量被缺省构造
在堆中缺省构造单个对象或对象数组,基本类型成员变量被初始化为适当类型的零值,类类型成员变量被缺省构造
对于已经定义至少一个构造函数的类,系统不会为其提供缺省构造函数
xxxxxxxxxx
451// nodefcons.cpp
2
3// 若已定义构造函数,则系统不再提供缺省构造函数
4
5
6
7using namespace std;
8
9class User {
10public:
11 // 已定义构造函数,系统不提供缺省构造函数
12
13 User(string name, int age) {
14 this->name = name;
15 this->age = age;
16 }
17
18 void print(void) {
19 cout << name << ", " << age << endl;
20 }
21
22private:
23 string name;
24 int age;
25};
26
27int main(void) {
28 User user1; // 编译错误,未定义缺省构造函数
29 user1.print();
30
31 User users1[3]; // 编译错误,未定义缺省构造函数
32 for (int i = 0; i < 3; ++i)
33 users1[i].print();
34
35 User* user2 = new User; // 编译错误,未定义缺省构造函数
36 user2->print();
37 delete user2;
38
39 User* users2 = new User[3]; // 编译错误,未定义缺省构造函数
40 for (int i = 0; i < 3; ++i)
41 users2[i].print();
42 delete[] users2;
43
44 return 0;
45}
有时必须自己定义缺省构造函数,即使它什么也不做,尤其是在使用数组或容器的时候。某些基于早期标准的编译器,可能不支持对对象数组的初始化语法
xxxxxxxxxx
471// hastodef.cpp
2
3// 有时必须自己定义缺省构造函数,即使它什么也不做,尤其是在使用数组或容
4// 器的时候。某些基于早期标准的编译器,可能不支持对对象数组的初始化语法
5
6
7
8using namespace std;
9
10class User {
11public:
12 // 自定义缺省构造函数
13 User(void) {}
14
15 User(string name, int age) {
16 this->name = name;
17 this->age = age;
18 }
19
20 void print(void) {
21 cout << name << ", " << age << endl;
22 }
23
24private:
25 string name;
26 int age;
27};
28
29int main (int argc, char* argv[]) {
30 User user1; // 编译通过
31 user1.print();
32
33 User users1[3]; // 编译通过
34 for (int i = 0; i < 3; ++i)
35 users1[i].print();
36
37 User* user2 = new User; // 编译通过
38 user2->print();
39 delete user2;
40
41 User* users2 = new User[3]; // 编译通过
42 for (int i = 0; i < 3; ++i)
43 users2[i].print();
44 delete[] users2;
45
46 return 0;
47}
在has-a关系中,缺省构造具有传染性
xxxxxxxxxx
461// hasacons1.cpp
2
3// 在has-a关系中,缺省构造具有传染性
4
5
6
7using namespace std;
8
9class Order {
10public:
11 // 已定义构造函数,系统不提供缺省构造函数
12
13 Order(int number) {
14 this->number = number;
15 }
16
17 int number;
18};
19
20class User {
21public:
22 // 未定义构造函数,系统提供缺省构造函数
23
24 void print(void) {
25 cout << name << ", " << age << ", " << order.number << endl;
26 }
27
28private:
29 string name;
30 int age;
31 Order order;
32};
33
34int main(void) {
35 // User类的缺省构造将引发其类类型成员变量order
36 // 被缺省构造,但后者并没有缺省构造函数
37
38 User user1; // 编译错误
39 user1.print();
40
41 User* user2 = new User; // 编译错误
42 user2->print();
43 delete user2;
44
45 return 0;
46}
因此,有时必须为一个类提供缺省构造函数,仅仅因为它可能作为另一个对象的子对象而被缺省构造
xxxxxxxxxx
471// hasacons2.cpp
2
3// 有时必须为一个类提供缺省构造函数,仅仅因为
4// 它可能作为另一个对象的子对象而被缺省构造
5
6
7
8using namespace std;
9
10class Order {
11public:
12 // 自定义缺省构造函数
13 Order(void) {}
14
15 Order(int number) {
16 this->number = number;
17 }
18
19 int number;
20};
21
22class User {
23public:
24 // 未定义构造函数,系统提供缺省构造函数
25
26 void print(void) {
27 cout << name << ", " << age << ", " << order.number << endl;
28 }
29
30private:
31 string name;
32 int age;
33 Order order;
34};
35
36int main(void) {
37 // User的缺省构造将以缺省方式构造其Order子对象
38
39 User user1; // 编译通过
40 user1.print();
41
42 User* user2 = new User; // 编译通过
43 user2->print();
44 delete user2;
45
46 return 0;
47}
若子对象不宜缺省构造,则需要为父对象提供缺省构造函数,并在其中显式地以非缺省方式构造该子对象
xxxxxxxxxx
471// hasacons3.cpp
2
3// 若子对象不宜缺省构造,则需要为父对象提供缺省构
4// 造函数,并在其中显式地以非缺省方式构造该子对象
5
6
7
8using namespace std;
9
10class Order {
11public:
12 // 已定义构造函数,系统不提供缺省构造函数
13
14 Order(int number) {
15 this->number = number;
16 }
17
18 int number;
19};
20
21class User {
22public:
23 // 自定义缺省构造函数,并显式地以非缺省方式构造其类类型成员变量
24 User(void) : order(1000) {}
25
26 void print(void) {
27 cout << name << ", " << age << ", " << order.number << endl;
28 }
29
30private:
31 string name;
32 int age;
33 Order order;
34};
35
36int main(void) {
37 // User的缺省构造将以非缺省方式构造其Order子对象
38
39 User user1; // 编译通过
40 user1.print();
41
42 User* user2 = new User; // 编译通过
43 user2->print();
44 delete user2;
45
46 return 0;
47}
类的常量和引用型成员变量必须被显式地初始化
xxxxxxxxxx
331// constref1.cpp
2
3// 类的常量和引用型成员变量必须被显式地初始化
4
5
6
7using namespace std;
8
9class User {
10public:
11 // 未定义构造函数,系统提供缺省构造函数
12
13 void print(void) {
14 cout << name << ", " << age << endl;
15 }
16
17private:
18 const string name;
19 int& age;
20};
21
22int main(void) {
23 // User类包含常量和引用型成员变量,且未被显式地初始化
24
25 User user1; // 编译错误
26 user1.print();
27
28 User* user2 = new User; // 编译错误
29 user2->print();
30 delete user2;
31
32 return 0;
33}
xxxxxxxxxx
361// constref2.cpp
2
3// 类的常量和引用型成员变量必须被显式地初始化
4
5
6
7using namespace std;
8
9int age = -1;
10
11class User {
12public:
13 // 在自定义构造函数中显式初始化常量和引用型成员变量
14 User(void) : name("Anonymous"), age(::age) {}
15
16 void print(void) {
17 cout << name << ", " << age << endl;
18 }
19
20private:
21 const string name;
22 int& age;
23};
24
25int main(void) {
26 // User类包含常量和引用型成员变量,且已被显式地初始化
27
28 User user1; // 编译通过
29 user1.print();
30
31 User* user2 = new User; // 编译通过
32 user2->print();
33 delete user2;
34
35 return 0;
36}
构造函数的调用顺序:基类的构造函数
析构函数的调用顺序:子类的析构函数
xxxxxxxxxx
511// consorder.cpp
2
3// 构造函数的调用顺序:基类->成员->子类
4// 析构函数的调用顺序:子类->成员->基类
5
6
7
8using namespace std;
9
10class Base {
11public:
12 Base(void) {
13 cout << "Base::Base() invoked" << endl;
14 }
15
16 ~Base(void) {
17 cout << "Base::~Base() invoked" << endl;
18 }
19};
20
21class Member {
22public:
23 Member(void) {
24 cout << "Member::Member() invoked" << endl;
25 }
26
27 ~Member(void) {
28 cout << "Member::~Member() invoked" << endl;
29 }
30};
31
32class Super : public Base
33{
34public:
35 Super(void) {
36 cout << "Super::Super() invoked" << endl;
37 }
38
39 ~Super(void) {
40 cout << "Super::~Super() invoked" << endl;
41 }
42
43private:
44 Member member;
45};
46
47int main(void) {
48 Super super;
49
50 return 0;
51}
数组元素的构造顺序:低地址
数组元素的析构顺序:高地址
xxxxxxxxxx
271// arrayconsorder.cpp
2
3// 数组元素的构造顺序:低地址->高地址
4// 数组元素的析构顺序:高地址->低地址
5
6
7
8using namespace std;
9
10class Object {
11public:
12 Object(void) {
13 cout << "Object::Object() invoked, " << this << endl;
14 }
15
16 ~Object(void) {
17 cout << "Object::~Object() invoked, " << this << endl;
18 }
19};
20
21int main(void) {
22 Object* objects = new Object[3];
23
24 delete[] objects;
25
26 return 0;
27}
xxxxxxxxxx
341// consconv.cpp
2
3// 支持自定义类型转换的构造函数
4
5
6
7using namespace std;
8
9class User {
10public:
11 // 支持从char*到User的类型转换
12 User(const char* name, int age = -1) {
13 this->name = name;
14 this->age = age;
15 }
16
17 void print(void) {
18 cout << name << ", " << age << endl;
19 }
20
21private:
22 string name;
23 int age;
24};
25
26int main(void) {
27 User user("Zaphod", 49);
28 user.print();
29
30 user = "Antony"; // char*->User
31 user.print();
32
33 return 0;
34}
通过在类的构造函数中使用初始化表,初始化该类的成员变量
xxxxxxxxxx
501// initlist.cpp
2
3// 通过在类的构造函数中使用初始化列表,初始化该类的成员变量
4
5
6
7using namespace std;
8
9class User {
10public:
11 // 带有初始化列表的构造函数
12 User(string name, int age) : name(name), age(age) {}
13
14 void print(void) {
15 cout << name << ", " << age << endl;
16 }
17
18private:
19 string name;
20 int age;
21};
22
23int main(void) {
24 User user1("Zaphod", 49);
25 user1.print();
26
27 User user2 = User("Antony", 37);
28 user2.print();
29
30 User* user3 = new User("Stephen", 35);
31 user3->print();
32 delete user3;
33
34 User users1[] = {
35 User("Zaphod", 49),
36 User("Antony", 37),
37 User("Stephen", 35)};
38 for (int i = 0; i < 3; ++i)
39 users1[i].print();
40
41 User* users2 = new User[] {
42 User("Zaphod", 49),
43 User("Antony", 37),
44 User("Stephen", 35)};
45 for (int i = 0; i < 3; ++i)
46 users2[i].print();
47 delete[] users2;
48
49 return 0;
50}
类的成员变量按其在类中的定义顺序被依次初始化,而非其出现在初始化表中的顺序
xxxxxxxxxx
291// initorder1.cpp
2
3// 类的成员变量按其在类中的定义顺序被依次初始化,而非其出现在初始化表中的顺序
4
5
6
7using namespace std;
8
9class MyString {
10public:
11 // 按照成员变量的定义顺序,先初始化len,后初始化str,
12 // 因此通过str.size()初始化len的做法显然是错误的
13 MyString(const char* psz) : str(psz), len(str.size()) {}
14
15 void show(void) {
16 cout << str << ", " << len << endl;
17 }
18
19private:
20 int len;
21 string str;
22};
23
24int main(void) {
25 MyString str("hello world");
26 str.show();
27
28 return 0;
29}
xxxxxxxxxx
301// initorder2.cpp
2
3// 类的成员变量按其在类中的定义顺序被依次初始化,而非其出现在初
4// 始化表中的顺序,因此在初始化表中,应尽量避免成员变量间的耦合
5
6
7
8
9
10using namespace std;
11
12class MyString {
13public:
14 MyString(const char* psz) : str(psz), len(strlen(psz)) {}
15
16 void show(void) {
17 cout << str << ", " << len << endl;
18 }
19
20private:
21 int len;
22 string str;
23};
24
25int main(void) {
26 MyString str("hello world ");
27 str.show();
28
29 return 0;
30}
类的常量和引用型成员变量,必须初始化表中初始化
类的成员子对象和基类子对象,如果没有缺省构造函数,也必须在初始化表中初始化
一般而言,关键字this是一个指针,对于一般成员函数,它指向调用该函数的对象,而对于构造和析构函数,它则指向这个正在被创建和销毁的对象
xxxxxxxxxx
141// calling.h
2
3// 声明Student类
4
5
6
7class Student {
8public:
9 Student(const string& name);
10
11 void who(void) const;
12
13 string name;
14};
xxxxxxxxxx
271// calling.cpp
2
3// 实现Student类
4
5
6
7
8
9using namespace std;
10
11Student::Student(const string& name) : name(name) {}
12/*
13void Student::who(void) const {
14 cout << "我是" << name << "。" << endl;
15}
16*/
17extern "C" void _ZNK7Student3whoEv(const Student* _this) {
18 cout << "我是" << _this->name << "。" << endl;
19}
20
21int main(void) {
22 Student student("张飞");
23
24 student.who();
25
26 return 0;
27}
很多时候,为了方便起见,常常希望一个类的某个数据成员和这个类的构造函数的相应参数取相同的标识符。为此,在构造函数的内部,通过this关键字,可以将二者有效地区分开来
xxxxxxxxxx
381// this.cpp
2
3// 显式使用this指针
4
5
6
7using namespace std;
8
9class User {
10public:
11 User(string name, int age) {
12 cout << "User::User(): this=" << this << endl;
13
14 this->name = name;
15 this->age = age;
16 }
17
18 void print(void) const {
19 cout << "User::print(): this=" << this << endl;
20
21 cout << name << ", " << age << endl;
22 cout << this->name << ", " << this->age << endl;
23 }
24
25private:
26 string name;
27 int age;
28};
29
30int main(void) {
31 User user("Paul", 33);
32
33 cout << "main(): &user="<< &user << endl;
34
35 user.print();
36
37 return 0;
38}
基于this指针的自身引用还被广泛地应用于那些支持多重串联调用的函数中
xxxxxxxxxx
381// retthis.cpp
2
3// 从函数中返回this
4
5
6
7using namespace std;
8
9class Integer {
10public:
11 Integer(int value = 0) : value(value) {}
12
13 Integer& inc(int inc = 1) {
14 value += inc;
15 return *this;
16 }
17
18 Integer& dec(int dec = 1) {
19 value -= dec;
20 return *this;
21 }
22
23 void show(void) const {
24 cout << value << endl;
25 }
26
27private:
28 int value;
29};
30
31int main(void) {
32 Integer i;
33
34 i.inc().inc(2).inc(3).show();
35 i.dec().dec(2).dec(3).show();
36
37 return 0;
38}
将this指针作为函数的参数,可协助完成对象间的交互
xxxxxxxxxx
421// paramthis.cpp
2
3// 将this指针作为函数的参数
4
5
6
7using namespace std;
8
9class Student;
10
11class Teacher {
12public:
13 void educate(Student* student);
14
15 void reply(const char* answer) {
16 cout << answer << endl;
17 }
18};
19
20class Student {
21public:
22 void ask(const char* question, Teacher* teacher) {
23 cout << question << endl;
24
25 teacher->reply("一般而言,关键字this是一个指针,对于一般成员函数,"
26 "它指向调用该函数的对象,而对于构造和析构函数,"
27 "它则指向这个正在被创建和销毁的对象。");
28 }
29};
30
31void Teacher::educate(Student* student) {
32 student->ask("什么是this指针?", this); // 把自己传给student
33}
34
35int main (void) {
36 Teacher teacher;
37 Student student;
38
39 teacher.educate(&student);
40
41 return 0;
42}
常量型成员函数中的this指针为常量型,以此防止对成员变量的意外修改。对常量型对象只能调用其常量型成员函数
xxxxxxxxxx
471// constfunc.cpp
2
3// 常量型成员函数中的this指针为常指针,以此防止对成员变量的意外修改
4
5
6
7using namespace std;
8
9class Date {
10public:
11 Date(int year, int mon, int day) : year(year), mon(mon), day(day) {}
12
13 void update(int year, int mon, int day) {
14 this->year = year;
15 this->mon = mon;
16 this->day = day;
17 }
18
19 void show(void) const {
20 // cout << year-- << mon << "-" << day << endl; // 编译错误,this指针为常指针
21 cout << year << "-" << mon << "-" << day << endl;
22 }
23
24private:
25 int year, mon, day;
26};
27
28int main(void) {
29 Date d1(2024, 6, 24);
30 d1.show();
31
32 // 对常量型对象只能调用其常量型成员函数
33
34 const Date d2 = d1;
35 d2.show();
36 // d2.update(2025, 7, 25); // 编译错误
37
38 const Date& d3 = d2;
39 d3.show();
40 // d3.update(2025, 7, 25); // 编译错误
41
42 const Date* d4 = &d3;
43 d4->show();
44 // d4->update(2025, 7, 25); // 编译错误
45
46 return 0;
47}
被声明为mutable的成员变量可以被常量型成员函数修改
xxxxxxxxxx
371// mutable.cpp
2
3// 被声明为mutable的成员变量可以被常量型成员函数修改
4
5
6
7using namespace std;
8
9class Document {
10public:
11 Document(void) : printTimes(0) {}
12
13 void print(void) const {
14 if (printTimes >= 3) {
15 cout << "Unable to print over 3 times!" << endl;
16 return;
17 }
18
19 // ...
20
21 ++printTimes; // mutable成员变量可以被常量型成员函数修改
22 }
23
24private:
25 mutable unsigned int printTimes;
26};
27
28int main(void){
29 Document doc;
30
31 doc.print();
32 doc.print();
33 doc.print();
34 doc.print();
35
36 return 0;
37}
常量型成员函数和非常量型成员函数构成重载关系,通过常量型对象调用常量型成员函数,通过非常量型对象调用非常量型成员函数,但如果没有非常量型成员函数,通过非常量型对象也能调用常量型成员函数
xxxxxxxxxx
331// constover.cpp
2
3// 常量型成员函数和非常量型成员函数构成重载关系
4
5
6
7using namespace std;
8
9class A {
10public:
11 // 非常量型版本
12 // void foo(void) {
13 // cout << "A::foo() invoked" << endl;
14 // }
15
16 // 常量型版本
17 void foo(void) const {
18 cout << "A::foo() const invoked" << endl;
19 }
20};
21
22int main(void) {
23 A a1; // 非常量型对象
24 a1.foo(); // 匹配到非常量型版本
25
26 const A& a2 = a1; // 常量型对象(引用)
27 a2.foo(); // 匹配到常量型版本
28
29 A* a3 = const_cast<A*>(&a2); // 非常量型对象(指针)
30 a3->foo(); // 匹配到非常量型版本
31
32 return 0;
33}
xxxxxxxxxx
51class 类名 {
2 ~类名(void) {
3 函数体;
4 }
5};
析构函数没有参数,因此无法重载。
xxxxxxxxxx
441// destructor.cpp
2
3// 析构函数的基本用法
4
5
6
7using namespace std;
8
9class Array {
10public:
11 Array(size_t size) : array(new int[size]), size(size) {
12 cout << "Array::Array() invoked, size=" << size << endl;
13 }
14
15 // 析构函数,没有参数,不能重载
16 ~Array(void) {
17 cout << "Array::~Array() invoked, size=" << size << endl;
18
19 delete[] array; // 释放在构造函数中分配的内存
20 }
21
22private:
23 int* array;
24 size_t size;
25};
26
27int main(void) {
28 Array a1(10);
29
30 {
31 Array a2(20);
32 }
33
34 Array* a3 = new Array(30);
35
36 Array* a4 = new Array[] {Array(40), Array(50), Array(60)};
37
38 delete[] a4;
39
40 delete a3;
41 // delete a3; // 运行错误,一个对象的析构函数只调用一次
42
43 return 0;
44}
对于未定义析构函数的类,系统会提供缺省析构函数,该析构函数会调用成员及基类的析构函数
xxxxxxxxxx
321// defdescan.cpp
2
3// 若未定义析构函数,系统会提供缺省析构函数,该
4// 析构函数会调用其成员及基类子对象的析构函数
5
6
7
8using namespace std;
9
10class A {
11public:
12 A(void) {
13 cout << "A::A() invoked" << endl;
14 }
15
16 ~A(void) {
17 cout << "A::~A() invoked" << endl;
18 }
19};
20
21class B {
22 // 缺省析构函数负责调用A的析构函数,销毁其A类子对象
23
24private:
25 A a;
26};
27
28int main(void) {
29 B b;
30
31 return 0;
32}
缺省析构函数不负责释放动态分配的资源
xxxxxxxxxx
341// defdescannot.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 {
21public:
22 B(void) : a(new A) {}
23
24 // 缺省析构函数不负责销毁成员a指向的A类对象
25
26private:
27 A* a;
28};
29
30int main(void) {
31 B b;
32
33 return 0;
34}
对于动态分配的资源,必须通过自己定义的析构函数进行释放
xxxxxxxxxx
371// mustdes.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 {
21public:
22 B(void) : a(new A) {}
23
24 // 自定义析构函数负责销毁成员a指向的A类对象
25 ~B(void) {
26 delete a;
27 }
28
29private:
30 A* a;
31};
32
33int main(void) {
34 B b;
35
36 return 0;
37}
xxxxxxxxxx
461// desmore.cpp
2
3// 析构函数所释放的资源不仅限于内存资源
4
5
6
7
8
9
10using namespace std;
11
12class File {
13public:
14 File(const char* filename, const char* mode) : fp(fopen(filename, mode)) {
15 assert(fp);
16
17 cout << "File::File(): Open file" << endl;
18 }
19
20 ~File(void) {
21 fclose(fp); // 关闭文件
22
23 cout << "File::~File(): Close file" << endl;
24 }
25
26 size_t read(void* buffer, size_t count) {
27 return fread(buffer, 1, count, fp);
28 }
29
30 size_t write(const void* buffer, size_t count) {
31 return fwrite(buffer, 1, count, fp);
32 }
33
34private:
35 FILE* fp;
36};
37
38int main(void) {
39 File file("./desmore.cpp", "r");
40
41 char buffer[1024] = {};
42 file.read(buffer, sizeof(buffer) - 1);
43 cout << buffer << endl;
44
45 return 0;
46}
默认的拷贝构造就是按字节复制一份
xxxxxxxxxx
381// copybytes.cpp
2
3// 默认方式的拷贝构造就是按字节复制一份
4
5
6
7
8
9using namespace std;
10
11class A {
12public:
13 A (int n, double d, const char* s) : n(n), d(d) {
14 strcpy(this->s, s);
15 }
16
17 // 未定义拷贝构造函数,采用默认的字节复制的方式进行拷贝构造
18
19 void show(void) const {
20 cout << n << ", " << d << ", " << s << endl;
21 }
22
23private:
24 int n;
25 double d;
26 char s[1024];
27};
28
29int main(void) {
30 A a1(123, 4.56, "789");
31 a1.show();
32
33 // A a2(a1); // 拷贝构造
34 A a2 = a1; // 拷贝构造
35 a2.show();
36
37 return 0;
38}
默认的拷贝构造不能实现深拷贝
xxxxxxxxxx
431// defcpcons.cpp
2
3// 默认的字节复制方式的拷贝构造不能实现深拷贝
4
5
6
7
8
9using namespace std;
10
11class A {
12public:
13 A (int n, double d, const char* s) : n(n), d(d),
14 s(strcpy(new char[strlen(s)+1], s)) {}
15
16 // 未定义拷贝构造函数,采用默认的字节复制的方式进行拷贝构造
17
18 ~A (void) {
19 cout << "A::~A(): s=" << static_cast<void*>(s) << endl;
20 delete[] s;
21 }
22
23 void show(void) const {
24 cout << n << ", " << d << ", " << s << endl;
25 }
26
27private:
28 int n;
29 double d;
30 char* s;
31};
32
33int main(void) {
34 A a1(123, 4.56, "789");
35 a1.show();
36
37 // 拷贝构造
38 A a2 = a1; // 字节复制方式的拷贝构造将导致a1和a2中的s指向同一块内存,
39 // 该内存在两个对象的析构函数中各被释放一次,导致崩溃
40 a2.show();
41
42 return 0;
43}
自定义拷贝构造函数,实现对象间的深拷贝,进而获得完整意义上的副本
xxxxxxxxxx
441// cpcons.cpp
2
3// 通过自定义的拷贝构造函数,可实现对象间的深拷贝,进而获得完整意义上的副本
4
5
6
7
8
9using namespace std;
10
11class A {
12public:
13 A (int n, double d, const char* s) : n(n), d(d),
14 s(strcpy(new char[strlen(s)+1], s)) {}
15
16 // 自定义的支持深拷贝的拷贝构造函数
17 A (const A& a) : n(a.n), d(a.d),
18 s(strcpy(new char[strlen(a.s)+1], a.s)) {}
19
20 ~A (void) {
21 cout << "A::~A(): s=" << static_cast<void*>(s) << endl;
22 delete[] s;
23 }
24
25 void show(void) const {
26 cout << n << ", " << d << ", " << s << endl;
27 }
28
29private:
30 int n;
31 double d;
32 char* s;
33};
34
35int main(void) {
36 A a1(123, 4.56, "789");
37 a1.show();
38
39 // 拷贝构造
40 A a2 = a1; // a1和a2中的s各自指向独立的内存,在各自的析构函数中被释放
41 a2.show();
42
43 return 0;
44}
自定义 | 系统缺省提供 |
---|---|
无 | 缺省构造函数和拷贝构造函数 |
除拷贝构造以外的其它构造函数 | 拷贝构造函数 |
拷贝构造函数 | 无 |
构造对象的副本
以对象为参数调用函数
从函数中返回对象
以对象的方式捕获异常
xxxxxxxxxx
531// whencpcons.cpp
2
3// 拷贝构造的时机:
4
5// 1) 构造对象的副本
6// 2) 以对象为参数调用函数
7// 3) 从函数中返回对象
8// 4) 以对象的方式捕获异常
9
10
11
12using namespace std;
13
14class A
15{
16public:
17 A (void) {}
18
19 A (const A& a) {
20 cout << "A::A(A) invoked" << endl;
21 }
22};
23
24void foo(A a) {
25 cout << "foo() invoked" << endl;
26}
27
28A bar(void) {
29 cout << "bar() invoked" << endl;
30
31 A a;
32 return a;
33}
34
35int main(void) {
36 A a1;
37
38 A a2 = a1; // 构造对象的副本
39
40 foo(a2); // 以对象为参数调用函数
41
42 bar(); // 从函数中返回对象
43
44 try {
45 throw A();
46 }
47 catch (A a) { // 以对象的方式捕获异常
48 }
49
50 return 0;
51}
52
53// g++ -fno-elide-constructors whencpcons.cpp
自定义拷贝构造只能解决创建对象副本时的深拷贝问题,默认的拷贝赋值仍然是按字节复制
xxxxxxxxxx
491// defcpassign.cpp
2
3// 拷贝构造只能解决构造对象副本时的深拷贝问题,默认方式的拷贝赋值仍然是按字节复制
4
5
6
7
8
9using namespace std;
10
11class A {
12public:
13 A (int n, double d, const char* s) : n(n), d(d),
14 s(strcpy(new char[strlen(s)+1], s)) {}
15
16 A (const A& a) : n(a.n), d(a.d),
17 s(strcpy(new char[strlen(a.s)+1], a.s)) {}
18
19 // 未定义拷贝赋值操作符,采用默认的字节复制的方式进行拷贝赋值
20
21 ~A (void) {
22 cout << "A::~A(): s=" << static_cast<void*>(s) << endl;
23 delete[] s;
24 }
25
26 void show(void) const {
27 cout << n << ", " << d << ", " << s << endl;
28 }
29
30private:
31 int n;
32 double d;
33 char* s;
34};
35
36int main(void) {
37 A a1(123, 4.56, "789");
38 a1.show();
39
40 A a2(987, 6.54, "321");
41 a2.show();
42
43 // 拷贝赋值
44 a2 = a1; // 字节复制方式的拷贝赋值将导致a1和a2中的s指向同一块内存,
45 // 该内存在两个对象的析构函数中各被释放一次,导致崩溃
46 a2.show();
47
48 return 0;
49}
自定义拷贝赋值操作符函数,实现对象间的深拷贝,进而获得完整意义上的副本
xxxxxxxxxx
581// cpassign1.cpp
2
3// 通过自定义的拷贝赋值操作符函数,可实现对象间的深拷贝,进而获得完整意义上的副本
4
5
6
7
8
9using namespace std;
10
11class A {
12public:
13 A (int n, double d, const char* s) : n(n), d(d),
14 s(strcpy(new char[strlen(s)+1], s)) {}
15
16 A (const A& a) : n(a.n), d(a.d),
17 s(strcpy(new char[strlen(a.s)+1], a.s)) {}
18
19 // 自定义的支持深拷贝的拷贝赋值操作符函数
20 void operator=(const A& a) {
21 if (&a != this) { // 防止自赋值
22 n = a.n;
23 d = a.d;
24
25 delete[] s;
26
27 s = strcpy(new char[strlen(a.s)+1], a.s);
28 }
29 }
30
31 ~A (void) {
32 cout << "A::~A(): s=" << static_cast<void*>(s) << endl;
33 delete[] s;
34 }
35
36 void show(void) const {
37 cout << n << ", " << d << ", " << s << endl;
38 }
39
40private:
41 int n;
42 double d;
43 char* s;
44};
45
46int main(void) {
47 A a1(123, 4.56, "789");
48 a1.show();
49
50 A a2(987, 6.54, "321");
51 a2.show();
52
53 // 拷贝赋值
54 a2 = a1; // a1和a2中的s各自指向独立的内存,在各自的析构函数中被释放
55 a2.show();
56
57 return 0;
58}
更好的拷贝赋值操作符函数,支持连续赋值
xxxxxxxxxx
651// cpassign2.cpp
2
3// 更好的拷贝赋值操作符函数,支持连续赋值
4
5
6
7
8
9using namespace std;
10
11class A {
12public:
13 A (int n, double d, const char* s) : n(n), d(d),
14 s(strcpy(new char[strlen(s)+1], s)) {}
15
16 A (const A& a) : n(a.n), d(a.d),
17 s(strcpy(new char[strlen(a.s)+1], a.s)) {}
18
19 // 更好的支持连续赋值拷贝赋值操作符函数
20 A& operator= (const A& a) {
21 if (&a != this) {
22 n = a.n;
23 d = a.d;
24
25 A _a = a;
26
27 swap(s, _a.s);
28 }
29
30 return *this; // 返回自引用
31 }
32
33 ~A (void) {
34 cout << "A::~A(): s=" << static_cast<void*>(s) << endl;
35 delete[] s;
36 }
37
38 void show(void) const {
39 cout << n << ", " << d << ", " << s << endl;
40 }
41
42private:
43 int n;
44 double d;
45 char* s;
46};
47
48int main(void) {
49 A a1(123, 4.56, "789");
50 a1.show();
51
52 A a2(987, 6.54, "321");
53 a2.show();
54
55 A a3(222, 5.55, "888");
56 a3.show();
57
58 // 连续拷贝赋值
59 a3 = a2 = a1; // a1->a2, a2->a3
60 // (a3 = a2) = a1; // a2->a3, a1->a3
61 a2.show();
62 a3.show();
63
64 return 0;
65}
静态成员变量的定义和初始化,只能在类的外部而不能在构造函数中进行
静态成员变量被该类的多个对象实例共享
访问静态成员,既可以通过类也可以通过对象,但最好通过类
静态成员函数只能访问静态成员,而非静态成员函数既可以访问静态成员,也可以访问非静态成员
xxxxxxxxxx
561// staticmem.cpp
2
3// 类的静态成员属于类而非静态成员属于对象,类在
4// 对象间共享并被对象所访问,但类不能访问对象
5
6
7
8using namespace std;
9
10class Account {
11public:
12 Account (const string& name, double balance) :
13 name(name), balance(balance) {}
14
15 static void setRate(double rate) {
16 // 静态成员函数只能访问静态成员
17 Account::rate = rate;
18 }
19
20 static double getRate(void) {
21 // 静态成员函数只能访问静态成员
22 return rate;
23 }
24
25 double settle(void) {
26 // 非静态成员函数既可以访问静态成员,也可以访问非静态成员
27 return balance *= (1 + rate / 100.);
28 }
29
30private:
31 string name;
32 double balance;
33 static double rate; // 所有账户对象均共享同一利率
34};
35
36// 静态成员变量需在类外定义并初始化
37double Account::rate = 0.5;
38
39int main(void) {
40 Account acc1("Richard Lee", 10000.0);
41 Account acc2("Marshall Cline", 10.0);
42
43 acc1.setRate(0.4); // 通过对象访问静态成员
44 cout << Account::getRate() << endl; // 通过类访问静态成员
45
46 for (int i = 0; i < 3; ++i)
47 cout << acc1.settle() << ", " << acc2.settle() << endl;
48
49 Account::setRate(0.6); // 通过类访问静态成员
50 cout << acc1.getRate() << endl; // 通过对象访问静态成员
51
52 for (int i = 0; i < 3; ++i)
53 cout << acc1.settle() << ", " << acc2.settle() << endl;
54
55 return 0;
56}
饿汉单例
xxxxxxxxxx
361// hungry.cpp
2
3// 饿汉单例
4
5
6
7using namespace std;
8
9class A {
10public:
11 // 获取唯一对象实例的静态方法
12 static A& inst(void) {
13 return a;
14 }
15
16private:
17 // 构造函数私有化
18 A(void) {}
19 A(const A& a) {}
20
21 static A a; // 唯一的对象实例
22};
23
24A A::a;
25
26int main(void) {
27 A& a1 = A::inst();
28 A& a2 = A::inst();
29 A& a3 = A::inst();
30 cout << &a1 << ", " << &a2 << ", " << &a3 << endl;
31
32 // A a4; // 直接构造被禁止
33 // A a5(a3); // 拷贝构造被禁止
34
35 return 0;
36}
懒汉单例
xxxxxxxxxx
381// lazy.cpp
2
3// 懒汉单例
4
5
6
7using namespace std;
8
9class A {
10public:
11 // 获取唯一对象实例的静态方法
12 static A& inst(void) {
13 if (!a) a = new A;
14
15 return *a;
16 }
17
18private:
19 // 构造函数私有化
20 A(void) {}
21 A(const A& a) {}
22
23 static A* a; // 指向唯一对象实例的指针
24};
25
26A* A::a = NULL;
27
28int main(void) {
29 A& a1 = A::inst();
30 A& a2 = A::inst();
31 A& a3 = A::inst();
32 cout << &a1 << ", " << &a2 << ", " << &a3 << endl;
33
34 // A a4; // 直接构造被禁止
35 // A a5(a3); // 拷贝构造被禁止
36
37 return 0;
38}
定义语法:
xxxxxxxxxx
11成员变量类型 类名::*指针变量名;
例如:
xxxxxxxxxx
21string Account::*pname;
2double Account::*pbalance;
赋值及初始化语法:
xxxxxxxxxx
11指针变量名 = &类名::成员变量名;
例如:
xxxxxxxxxx
21pname = &Account::name;
2pbalance = &Account::balance;
解引用语法:
xxxxxxxxxx
21对象.*指针变量名
2对象指针->*指针变量名
例如:
xxxxxxxxxx
41Account acc("Richard Lee", 10000.0);
2cout << acc.*pname << endl;
3Account* pacc = &acc;
4cout << pacc->*pbalance << endl;
定义语法:
xxxxxxxxxx
11成员函数返回类型 (类名::*指针变量名)(形参表);
例如:
xxxxxxxxxx
11double (Account::*psettle)(void);
赋值及初始化语法:
xxxxxxxxxx
11指针变量名 = &类名::成员函数名;
例如:
xxxxxxxxxx
11psettle = &Account::settle;
解引用语法:
xxxxxxxxxx
21(对象.*指针变量名)(实参表)
2(对象指针->*指针变量名)(实参表)
例如:
xxxxxxxxxx
41Account acc("Richard Lee", 10000.0);
2cout << (acc.*psettle)() << endl;
3Account* pacc = &acc;
4cout << (pacc->*psettle)() << endl;
xxxxxxxxxx
71double* prate = &Account::rate;
2void (*psetRate)(double) = &Account::setRate;
3double (*pgetRate)(void) = &Account::getRate;
4
5cout << *prate << endl;
6(*psetRate)(0.4);
7cout << pgetRate() << endl;
xxxxxxxxxx
581// memptr.cpp
2
3// 指向成员的指针
4
5
6
7using namespace std;
8
9class Account {
10public:
11 Account (const string& name, double balance) :
12 name(name), balance(balance) {}
13
14 static void setRate(double rate) {
15 Account::rate = rate;
16 }
17
18 static double getRate(void) {
19 return rate;
20 }
21
22 double settle(void) {
23 return balance *= (1 + rate / 100.);
24 }
25
26 string name;
27 double balance;
28 static double rate;
29};
30
31double Account::rate = 0.5;
32
33int main(void) {
34 string Account::*pname = &Account::name;
35 double Account::*pbalance = &Account::balance;
36 double* prate = &Account::rate;
37
38 void (*psetRate)(double) = &Account::setRate;
39 double (*pgetRate)(void) = &Account::getRate;
40 double (Account::*psettle)(void) = &Account::settle;
41
42 Account acc("Richard Lee", 10000.0), *pacc = &acc;
43 cout << acc.*pname << ", " << pacc->*pbalance << ", " << *prate << endl;
44
45 (*psetRate)(0.4);
46 cout << (*pgetRate)() << endl;
47
48 for (int i = 0; i < 3; ++i)
49 cout << (acc.*psettle)() << endl;
50
51 psetRate(0.6);
52 cout << pgetRate() << endl;
53
54 for (int i = 0; i < 3; ++i)
55 cout << (pacc->*psettle)() << endl;
56
57 return 0;
58}