友元(friend)是C++中的一种特殊机制,它允许一个类将对其非公有成员(private和protected)的访问权授予指定的函数或类。友元打破了类的封装性,但提供了更高的灵活性和运行效率。
友元分为三种类型:
友元函数
友元类
友元成员函数
友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员的非成员函数。
在类中声明友元函数的语法如下:
x1class ClassName {
2 // 可以在任何访问修饰符下声明
3 friend 返回类型 函数名(参数列表);
4};
5
6// 类外定义友元函数(不需要friend关键字)
7返回类型 函数名(参数列表) {
8 // 函数体
9}
xxxxxxxxxx
331
2
3using namespace std;
4
5class Point {
6private:
7 double x, y;
8
9public:
10 Point(double xx, double yy) { x = xx; y = yy; }
11 void Getxy() {
12 cout << "(" << x << "," << y << ")" << endl;
13 }
14
15 // 声明友元函数
16 friend double Distance(Point &a, Point &b);
17};
18
19// 定义友元函数
20double Distance(Point &a, Point &b) {
21 double dx = a.x - b.x; // 可以直接访问私有成员
22 double dy = a.y - b.y;
23 return sqrt(dx*dx + dy*dy);
24}
25
26int main() {
27 Point p1(3.0, 4.0), p2(6.0, 8.0);
28 p1.Getxy();
29 p2.Getxy();
30 double d = Distance(p1, p2); // 调用友元函数
31 cout << "Distance is " << d << endl;
32 return 0;
33}
友元类是指一个类可以访问另一个类的所有成员(包括私有成员和保护成员)的类。当一个类被声明为另一个类的友元时,这个类的所有成员函数都成为另一个类的友元函数。
xxxxxxxxxx
151class ClassA {
2 // 声明ClassB为友元类
3 friend class ClassB;
4
5private:
6 int data;
7};
8
9class ClassB {
10public:
11 void func(ClassA &a) {
12 // 可以访问ClassA的私有成员
13 a.data = 100;
14 }
15};
xxxxxxxxxx
321
2using namespace std;
3
4class CCar; // 前向声明
5
6class CDriver {
7public:
8 void ModifyCar(CCar *pCar); // 改装汽车
9};
10
11class CCar {
12private:
13 int price;
14
15 // 声明CDriver为友元类
16 friend class CDriver;
17};
18
19void CDriver::ModifyCar(CCar *pCar) {
20 pCar->price += 1000; // 可以访问CCar的私有成员
21 cout << "Car price after modification: " << pCar->price << endl;
22}
23
24int main() {
25 CCar car;
26 CDriver driver;
27
28 // 通过友元类访问私有成员
29 driver.ModifyCar(&car);
30
31 return 0;
32}
友元成员函数是指将一个类的某个成员函数声明为另一个类的友元,使该成员函数可以访问另一个类的私有成员。
xxxxxxxxxx
331
2using namespace std;
3
4class A; // 前向声明
5
6class B {
7public:
8 void set_show(int x, A &a); // 该函数将成为类A的友元函数
9};
10
11class A {
12public:
13 // 声明B类的set_show方法为友元
14 friend void B::set_show(int x, A &a);
15
16private:
17 int data;
18};
19
20// 定义B类的set_show方法
21void B::set_show(int x, A &a) {
22 a.data = x; // 可以访问A的私有成员
23 cout << "A's data: " << a.data << endl;
24}
25
26int main() {
27 A a;
28 B b;
29
30 b.set_show(100, a);
31
32 return 0;
33}
1. 运算符重载
当需要重载某些运算符(如<<
、>>
等)时,这些运算符通常需要访问类的私有成员,此时可以将它们声明为友元函数。
xxxxxxxxxx
161class Complex {
2private:
3 double real, imag;
4
5public:
6 Complex(double r = 0, double i = 0) : real(r), imag(i) {}
7
8 // 声明重载的<<运算符为友元
9 friend ostream& operator<<(ostream& os, const Complex& c);
10};
11
12// 重载<<运算符
13ostream& operator<<(ostream& os, const Complex& c) {
14 os << c.real << "+" << c.imag << "i"; // 访问私有成员
15 return os;
16}
2. 需要访问多个类的私有成员
当一个函数需要同时访问多个类的私有成员时,可以将该函数声明为这些类的友元。
3. 提高性能
在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递、类型检查和安全性检查等都需要时间开销,使用友元可以提高程序的运行效率。
4. 辅助类和工具类
当设计辅助类或工具类来操作主类的内部数据时,可以将辅助类声明为主类的友元。
友元关系不能被继承:如果类B是类A的友元,类C继承自类B,类C不会自动成为类A的友元。
友元关系是单向的:如果类B是类A的友元,类A不一定是类B的友元,除非有明确声明。
友元关系不具有传递性:如果类B是类A的友元,类C是类B的友元,类C不会自动成为类A的友元。
友元声明位置:友元声明可以出现在类中的任何地方(private、protected或public部分),不受访问控制影响。
优点
提高程序运行效率:减少了类型检查和安全性检查等时间开销。
增加灵活性:使程序可以在封装和快速性方面做合理选择。
便于实现需要访问多个类私有成员的功能:可以灵活地实现需要访问若干类的私有或受保护成员才能完成的任务。
便于与非面向对象语言混合编程:便于与其他不支持类概念的语言(如C语言、汇编等)进行混合编程。
缺点
破坏封装性:友元机制破坏了类的封装性和数据隐藏性,使得非成员函数可以访问类的私有成员。
降低可维护性:过度使用友元会使代码结构变得复杂,难以维护。
增加耦合性:友元增加了类之间的耦合度,不利于代码的模块化。
Tip
谨慎使用:为了确保数据的完整性以及数据封装与隐藏的原则,建议尽量不使用或少使用友元。
合理场景:在需要提高性能、实现运算符重载或需要访问多个类私有成员的情况下,可以考虑使用友元。
友元声明位置:通常,将友元声明成组地放在类定义的开始或结尾是个好主意,以便于代码阅读和维护。
避免过度使用:过度使用友元会使代码难以理解和维护,应该在确实需要的情况下才使用。
加号(+)是一个典型的双目运算符,需要两个操作数:一个在加号前,一个在加号后。在C++中,我们可以通过两种方式实现+运算符的重载:
类成员函数方式
全局函数方式
通过类成员函数实现+运算符重载
当使用类成员函数实现+运算符重载时,函数原型如下:
xxxxxxxxxx
11Class_Name operator+(const Class_Name& other);
这种方式下,左操作数是调用该成员函数的对象(this),右操作数作为参数传入。
xxxxxxxxxx
321
2using namespace std;
3
4class Person {
5public:
6 Person();
7 Person(int val);
8 Person operator+(const Person& p); // 运算符重载函数声明
9private:
10 int m_age;
11};
12
13int main() {
14 Person p1;
15 Person p2;
16 Person p3 = p1 + p2; // 重载后的效果
17 return 0;
18}
19
20Person::Person() :m_age(10) {
21 cout << "无参构造函数" << endl;
22}
23
24Person::Person(int val) : m_age(val) {
25 cout << "有参构造函数" << endl;
26}
27
28Person Person::operator+(const Person& p) { // 运算符重载实现
29 Person tmp;
30 tmp.m_age = this->m_age + p.m_age;
31 return tmp;
32}
在上面的例子中,执行p1 + p2
时,实际上调用的是p1.operator+(p2)
,返回一个新的Person对象,其m_age值为p1和p2的m_age之和。
通过全局函数实现+运算符重载
全局函数方式的运算符重载函数原型如下:
xxxxxxxxxx
11Class_Name operator+(const Class_Name& left, const Class_Name& right);
这种方式下,左右操作数都作为参数传入函数。
xxxxxxxxxx
251
2using namespace std;
3
4class xiMeng {
5public:
6 int M_A;
7 int M_B;
8 // 这里不使用成员函数重载
9};
10
11// 通过全局函数实现运算符重载
12xiMeng operator+(xiMeng& p1, xiMeng& p2) {
13 xiMeng temp;
14 temp.M_A = p1.M_A + p2.M_A;
15 temp.M_B = p1.M_B + p2.M_B;
16 return temp;
17}
18
19// 运算符重载也可以发生函数重载
20xiMeng operator+(xiMeng& p, int num) {
21 xiMeng temp;
22 temp.M_A = p.M_A + num;
23 temp.M_B = p.M_B + num;
24 return temp;
25}
Tip
成员函数方式:
左操作数必须是类的对象
可以访问类的私有成员
适合当左操作数必须是该类对象的情况
全局函数方式:
左右操作数可以是不同类型
需要访问私有成员时,可以将函数声明为友元
适合需要支持交换律的情况(如 a+b = b+a)
适合左操作数不是该类对象的情况(如 5 + obj)
Note
不能改变运算符的优先级和结合性
不能改变运算符的操作数个数
至少有一个操作数是用户定义的类型
不能创建新的运算符
某些运算符不能被重载(如 :: 、. 、.* 、?: 等)
我将搜索关于C++中+=运算符重载的相关信息,以便提供详细的解释和示例代码。
toolName: web_search
status: success
query: C++ += 运算符重载 示例
重载+=
运算符的基本语法是:
xxxxxxxxxx
11returnType operator+=(const ParameterType& param);
作为类成员函数
作为成员函数重载+=
运算符时,左操作数隐式地是当前对象(this
指针),右操作数作为参数传入。
xxxxxxxxxx
231class MyClass {
2private:
3 int value;
4
5public:
6 MyClass(int val) : value(val) {}
7
8 // 重载 += 运算符作为成员函数
9 MyClass& operator+=(const MyClass& other) {
10 this->value += other.value;
11 return *this;
12 }
13
14 // 也可以重载不同类型的参数
15 MyClass& operator+=(int num) {
16 this->value += num;
17 return *this;
18 }
19
20 int getValue() const {
21 return value;
22 }
23};
作为友元函数
虽然+=
运算符通常作为成员函数实现,但在某些情况下也可以作为友元函数实现:
xxxxxxxxxx
191class MyClass {
2private:
3 int value;
4
5public:
6 MyClass(int val) : value(val) {}
7
8 friend MyClass& operator+=(MyClass& left, const MyClass& right);
9
10 int getValue() const {
11 return value;
12 }
13};
14
15// 作为友元函数实现 += 运算符
16MyClass& operator+=(MyClass& left, const MyClass& right) {
17 left.value += right.value;
18 return left;
19}
Note
+=
运算符重载函数通常返回对象的引用(&
),这样可以支持连续操作,如a += b += c
。
重载+=
运算符时,应该考虑同时重载+
运算符,保持一致性。
对于自定义类,重载+=
运算符可以提高代码的可读性和直观性。
返回引用类型可以避免创建不必要的临时对象,提高性能。
xxxxxxxxxx
421
2using namespace std;
3
4class Complex {
5private:
6 double real;
7 double imag;
8
9public:
10 Complex(double r = 0, double i = 0) : real(r), imag(i) {}
11
12 // 重载 += 运算符
13 Complex& operator+=(const Complex& other) {
14 this->real += other.real;
15 this->imag += other.imag;
16 return *this;
17 }
18
19 // 显示复数
20 void display() const {
21 cout << real << " + " << imag << "i" << endl;
22 }
23};
24
25int main() {
26 Complex c1(3.0, 4.0);
27 Complex c2(1.5, 2.5);
28
29 cout << "c1 = ";
30 c1.display();
31
32 cout << "c2 = ";
33 c2.display();
34
35 // 使用重载的 += 运算符
36 c1 += c2;
37
38 cout << "c1 += c2 的结果: ";
39 c1.display();
40
41 return 0;
42}
运行结果:
xxxxxxxxxx
31c1 = 3 + 4i
2c2 = 1.5 + 2.5i
3c1 += c2 的结果: 4.5 + 6.5i
++运算符有两种形式:前置++(如++a
)和后置++(如a++
)。这两种形式在行为和实现上有明显区别。
前置++:先增加变量的值,然后返回增加后的变量
后置++:先返回变量的当前值,然后再增加变量的值
C++通过函数参数来区分前置和后置++运算符重载
前置++:T& operator++()
,返回对象的引用(T&
),这样可以支持连续操作,如++(++a)
后置++:T operator++(int)
- 这里的int
参数是一个哑参数,仅用于区分后置版本,返回对象的值(T
),通常是修改前的对象副本
xxxxxxxxxx
571
2using namespace std;
3
4class Age {
5private:
6 int years;
7
8public:
9 // 构造函数
10 Age(int age = 0) : years(age) {}
11
12 // 前置++运算符重载
13 Age& operator++() {
14 // 先增加值
15 ++years;
16 // 返回增加后的对象引用
17 return *this;
18 }
19
20 // 后置++运算符重载
21 Age operator++(int) {
22 // 保存当前状态
23 Age temp = *this;
24 // 增加值
25 years++;
26 // 返回原始值(修改前的副本)
27 return temp;
28 }
29
30 // 用于输出的友元函数
31 friend ostream& operator<<(ostream& os, const Age& obj) {
32 os << "Age: " << obj.years;
33 return os;
34 }
35};
36
37int main() {
38 Age age(25);
39
40 // 测试后置++
41 cout << "原始年龄: " << age << endl;
42 Age oldAge = age++;
43 cout << "后置++后: " << age << endl;
44 cout << "后置++返回: " << oldAge << endl;
45
46 // 测试前置++
47 cout << "\n当前年龄: " << age << endl;
48 Age& newAge = ++age;
49 cout << "前置++后: " << age << endl;
50 cout << "前置++返回: " << newAge << endl;
51
52 // 验证前置++返回的引用
53 ++age = Age(30);
54 cout << "\n赋值后: " << age << endl;
55
56 return 0;
57}
前置++通常比后置++更高效 ,因为:
前置++:
直接修改对象
返回对象引用
无需创建临时对象
后置++:
需要创建临时对象保存原始状态
修改对象
返回临时对象
对于简单的内置类型(如int),性能差异很小。但对于复杂的用户定义类型,前置++的性能优势更为明显。
Tip
同时实现前置和后置版本以保持一致性
优先使用前置++,特别是对于迭代器和复杂对象
前置++返回引用,后置++返回值
后置++的实现应该调用前置++,以避免代码重复
Note
前置++:T& operator++()
,先增加再返回引用
后置++:T operator++(int)
,先返回副本再增加
[]
运算符(下标运算符)是 C++ 中常用的运算符之一,它允许我们像访问数组元素一样访问自定义类型的对象。通过重载 []
运算符,我们可以为自定义类实现类似数组的访问语法,使代码更加直观和易于理解。
[]
运算符重载的基本语法如下:
xxxxxxxxxx
11返回类型 operator[](参数类型 参数名);
具体来说,有两种常见的形式:
xxxxxxxxxx
51// 非 const 版本,允许修改元素
2返回类型& operator[](参数类型 参数名);
3
4// const 版本,不允许修改元素
5const 返回类型& operator[](参数类型 参数名) const;
Note
必须是成员函数:[]
运算符重载必须定义为类的成员函数,不能是全局函数。
通常返回引用:为了支持赋值操作(如 obj[i] = value
),通常返回引用类型。
提供 const 版本:为了支持 const 对象的访问,通常还需要提供一个 const 版本的重载。
参数类型灵活:参数通常是整数类型(如 int),但也可以是其他类型(如字符串)。
边界检查:通常需要进行边界检查,防止越界访问。
简单的数组封装类
xxxxxxxxxx
641
2
3
4class MyArray {
5private:
6 int* data;
7 int size;
8
9public:
10 MyArray(int sz) : size(sz) {
11 data = new int[size]();
12 }
13
14 ~MyArray() {
15 delete[] data;
16 }
17
18 // 非 const 版本,可读可写
19 int& operator[](int index) {
20 if (index < 0 || index >= size) {
21 throw std::out_of_range("索引越界");
22 }
23 return data[index];
24 }
25
26 // const 版本,只读
27 const int& operator[](int index) const {
28 if (index < 0 || index >= size) {
29 throw std::out_of_range("索引越界");
30 }
31 return data[index];
32 }
33
34 int getSize() const {
35 return size;
36 }
37};
38
39int main() {
40 MyArray arr(5);
41
42 // 使用 [] 运算符赋值
43 for (int i = 0; i < arr.getSize(); ++i) {
44 arr[i] = i * 10;
45 }
46
47 // 使用 [] 运算符读取
48 for (int i = 0; i < arr.getSize(); ++i) {
49 std::cout << "arr[" << i << "] = " << arr[i] << std::endl;
50 }
51
52 // 使用 const 对象
53 const MyArray constArr = arr;
54 // constArr[0] = 100; // 错误:不能修改 const 对象的元素
55 std::cout << "constArr[2] = " << constArr[2] << std::endl;
56
57 try {
58 std::cout << arr[10] << std::endl; // 越界访问
59 } catch (const std::out_of_range& e) {
60 std::cout << "异常:" << e.what() << std::endl;
61 }
62
63 return 0;
64}
使用非整数类型作为索引
xxxxxxxxxx
461
2
3
4
5class Dictionary {
6private:
7 std::map<std::string, std::string> data;
8
9public:
10 // 非 const 版本
11 std::string& operator[](const std::string& key) {
12 return data[key]; // 利用 std::map 的 [] 运算符
13 }
14
15 // const 版本
16 const std::string& operator[](const std::string& key) const {
17 auto it = data.find(key);
18 if (it == data.end()) {
19 throw std::out_of_range("键不存在");
20 }
21 return it->second;
22 }
23
24 bool hasKey(const std::string& key) const {
25 return data.find(key) != data.end();
26 }
27};
28
29int main() {
30 Dictionary dict;
31
32 // 使用 [] 运算符添加/修改元素
33 dict["apple"] = "苹果";
34 dict["banana"] = "香蕉";
35 dict["orange"] = "橙子";
36
37 // 使用 [] 运算符读取元素
38 std::cout << "apple 的中文是:" << dict["apple"] << std::endl;
39 std::cout << "banana 的中文是:" << dict["banana"] << std::endl;
40
41 // 修改元素
42 dict["apple"] = "红苹果";
43 std::cout << "修改后,apple 的中文是:" << dict["apple"] << std::endl;
44
45 return 0;
46}
实现多维数组访问
xxxxxxxxxx
651
2
3
4class Matrix {
5private:
6 std::vector<std::vector<int>> data;
7 int rows, cols;
8
9public:
10 Matrix(int r, int c) : rows(r), cols(c) {
11 data.resize(rows);
12 for (int i = 0; i < rows; ++i) {
13 data[i].resize(cols, 0);
14 }
15 }
16
17 // 返回行引用,以支持二维访问
18 std::vector<int>& operator[](int row) {
19 if (row < 0 || row >= rows) {
20 throw std::out_of_range("行索引越界");
21 }
22 return data[row];
23 }
24
25 // const 版本
26 const std::vector<int>& operator[](int row) const {
27 if (row < 0 || row >= rows) {
28 throw std::out_of_range("行索引越界");
29 }
30 return data[row];
31 }
32
33 void print() const {
34 for (int i = 0; i < rows; ++i) {
35 for (int j = 0; j < cols; ++j) {
36 std::cout << data[i][j] << " ";
37 }
38 std::cout << std::endl;
39 }
40 }
41};
42
43int main() {
44 Matrix mat(3, 4);
45
46 // 使用 [][] 设置元素
47 for (int i = 0; i < 3; ++i) {
48 for (int j = 0; j < 4; ++j) {
49 mat[i][j] = i * 10 + j;
50 }
51 }
52
53 // 打印矩阵
54 std::cout << "矩阵内容:" << std::endl;
55 mat.print();
56
57 // 访问单个元素
58 std::cout << "mat[1][2] = " << mat[1][2] << std::endl;
59
60 // 修改元素
61 mat[1][2] = 100;
62 std::cout << "修改后 mat[1][2] = " << mat[1][2] << std::endl;
63
64 return 0;
65}
代理类模式
有时我们需要在访问元素时执行特殊操作(如写时复制、延迟计算等),可以使用代理类模式:
xxxxxxxxxx
731
2
3
4class StringArray {
5private:
6 std::string* data;
7 int size;
8
9 // 代理类,用于实现特殊的下标操作
10 class Proxy {
11 private:
12 StringArray& array;
13 int index;
14
15 public:
16 Proxy(StringArray& a, int i) : array(a), index(i) {}
17
18 // 赋值运算符,当执行 array[i] = value 时调用
19 Proxy& operator=(const std::string& value) {
20 if (index < 0 || index >= array.size) {
21 throw std::out_of_range("索引越界");
22 }
23
24 // 这里可以添加特殊处理逻辑
25 std::cout << "写入操作:将 " << value << " 写入位置 " << index << std::endl;
26 array.data[index] = value;
27 return *this;
28 }
29
30 // 转换运算符,当读取 array[i] 时调用
31 operator std::string() const {
32 if (index < 0 || index >= array.size) {
33 throw std::out_of_range("索引越界");
34 }
35
36 // 这里可以添加特殊处理逻辑
37 std::cout << "读取操作:从位置 " << index << " 读取 " << array.data[index] << std::endl;
38 return array.data[index];
39 }
40 };
41
42public:
43 StringArray(int sz) : size(sz) {
44 data = new std::string[size];
45 }
46
47 ~StringArray() {
48 delete[] data;
49 }
50
51 // [] 运算符返回代理对象
52 Proxy operator[](int index) {
53 return Proxy(*this, index);
54 }
55};
56
57int main() {
58 StringArray arr(3);
59
60 // 写入操作
61 arr[0] = "Hello";
62 arr[1] = "World";
63 arr[2] = "C++";
64
65 // 读取操作
66 std::string s1 = arr[0];
67 std::string s2 = arr[1];
68
69 // 组合操作
70 std::cout << "组合:" << s1 + " " + s2 + " " + std::string(arr[2]) << std::endl;
71
72 return 0;
73}
Note
内存管理:如果类管理动态内存,确保正确处理内存分配和释放,避免内存泄漏。
边界检查:始终进行边界检查,防止越界访问导致的未定义行为。
返回引用:通常返回引用以支持赋值操作,但要确保引用的对象生命周期合适。
const 正确性:提供 const 和非 const 版本的重载,以支持不同场景的使用。
异常安全:适当使用异常处理机制,确保在异常情况下不会导致资源泄漏。
在C++中,<<
运算符原本是位左移运算符,但在C++标准库中被重载用于输出流操作。通过重载这个运算符,我们可以为自定义类型定义输出格式,使其能够直接与std::cout
等输出流一起使用。
xxxxxxxxxx
11std::ostream& operator<<(std::ostream& os, const MyClass& obj);
1. 友元函数
xxxxxxxxxx
151class MyClass {
2private:
3 int _value;
4 std::string _name;
5
6public:
7 // 声明为友元函数,可以访问私有成员
8 friend std::ostream& operator<<(std::ostream& os, const MyClass& obj);
9};
10
11// 实现友元函数
12std::ostream& operator<<(std::ostream& os, const MyClass& obj) {
13 os << "名称: " << obj._name << ", 值: " << obj._value;
14 return os;
15}
2. 成员函数
xxxxxxxxxx
121class MyClass {
2private:
3 int _value;
4 std::string _name;
5
6public:
7 // 作为成员函数实现
8 std::ostream& operator<<(std::ostream& os) const {
9 os << "名称: " << _name << ", 值: " << _value;
10 return os;
11 }
12};
成员函数方式不常用,因为它改变了运算符的使用方式(obj << cout
而不是cout << obj
)。
Important
返回类型:返回std::ostream&
引用,允许链式调用(如cout << obj1 << obj2
)
参数:
第一个参数是输出流的引用
第二个参数通常是要输出的对象的常量引用
const修饰:第二个参数通常用const
修饰,表示不会修改对象
友元声明:通常在类内声明为友元,以访问私有成员
在继承体系中,派生类的<<
运算符可以调用基类的<<
运算符:
xxxxxxxxxx
71friend std::ostream& operator<<(std::ostream& os, const Derived& obj) {
2 // 先调用基类的<<运算符
3 os << static_cast<const Base&>(obj);
4 // 再输出派生类特有部分
5 os << ", 派生类成员: " << obj._derivedMember;
6 return os;
7}
xxxxxxxxxx
41MyClass obj("测试", 100);
2std::cout << obj << std::endl;
3// 输出:名称: 测试, 值: 100
4
在C++中,>>
运算符原本是位右移运算符,但在C++标准库中被重载用于输入流操作。通过重载这个运算符,我们可以为自定义类型定义输入格式,使其能够直接与std::cin
等输入流一起使用。
xxxxxxxxxx
11std::istream& operator>>(std::istream& is, MyClass& obj);
1. 友元函数
xxxxxxxxxx
211class MyClass {
2private:
3 int _value;
4 std::string _name;
5
6public:
7 // 声明为友元函数,可以访问私有成员
8 friend std::istream& operator>>(std::istream& is, MyClass& obj);
9};
10
11// 实现友元函数
12std::istream& operator>>(std::istream& is, MyClass& obj) {
13 is >> obj._name >> obj._value;
14
15 // 检查输入是否成功
16 if (!is) {
17 // 处理输入错误
18 }
19
20 return is;
21}
2. 成员函数
xxxxxxxxxx
121class MyClass {
2private:
3 int _value;
4 std::string _name;
5
6public:
7 // 作为成员函数实现
8 std::istream& operator>>(std::istream& is) {
9 is >> _name >> _value;
10 return is;
11 }
12};
成员函数方式不常用,因为它改变了运算符的使用方式(obj >> cin
而不是cin >> obj
)。
Important
返回类型:返回std::istream&
引用,允许链式调用(如cin >> obj1 >> obj2
)
参数:
第一个参数是输入流的引用
第二个参数是要输入的对象的非常量引用(因为需要修改对象)
错误处理:应该检查输入操作是否成功,并适当处理错误
友元声明:通常在类内声明为友元,以访问私有成员
输入验证:通常需要验证输入数据的有效性
xxxxxxxxxx
191std::istream& operator>>(std::istream& is, MyClass& obj) {
2 int tempValue;
3 std::string tempName;
4
5 // 先读取到临时变量
6 is >> tempName >> tempValue;
7
8 // 验证输入
9 if (is) {
10 // 输入有效,更新对象
11 obj._name = tempName;
12 obj._value = tempValue;
13 } else {
14 // 输入无效,将流设置为失败状态
15 is.setstate(std::ios::failbit);
16 }
17
18 return is;
19}
xxxxxxxxxx
101MyClass obj;
2std::cout << "请输入名称和值:";
3std::cin >> obj;
4
5// 检查输入是否成功
6if (std::cin) {
7 std::cout << "输入成功!" << std::endl;
8} else {
9 std::cout << "输入失败!" << std::endl;
10}
C++中有两种主要的成员访问运算符:点运算符(.
)和箭头运算符(->
)。这两个运算符用于访问类或结构体的成员(包括变量和函数)。
点运算符用于通过对象直接访问其成员。
xxxxxxxxxx
11对象名.成员名
用于访问普通对象(非指针)的成员
用于访问引用类型对象的成员
用于访问通过值传递的对象的成员
xxxxxxxxxx
181class Person {
2public:
3 std::string name;
4 void sayHello() {
5 std::cout << "你好,我是" << name << std::endl;
6 }
7};
8
9int main() {
10 Person person;
11 person.name = "张三"; // 使用点运算符访问成员变量
12 person.sayHello(); // 使用点运算符调用成员函数
13
14 Person& personRef = person;
15 personRef.name = "李四"; // 引用类型也使用点运算符
16
17 return 0;
18}
箭头运算符用于通过指针访问对象的成员。
xxxxxxxxxx
11指针名->成员名
用于访问指针所指向对象的成员
用于访问动态分配对象的成员
用于智能指针访问其管理对象的成员
xxxxxxxxxx
141int main() {
2 Person* personPtr = new Person();
3 personPtr->name = "王五"; // 使用箭头运算符访问指针所指对象的成员变量
4 personPtr->sayHello(); // 使用箭头运算符调用指针所指对象的成员函数
5
6 delete personPtr; // 不要忘记释放内存
7
8 // 使用智能指针
9 std::shared_ptr<Person> smartPtr = std::make_shared<Person>();
10 smartPtr->name = "赵六";
11 smartPtr->sayHello();
12
13 return 0;
14}
箭头运算符(->
)可以被重载,但有特殊规则:
xxxxxxxxxx
201class SmartPointer {
2private:
3 Person* ptr;
4
5public:
6 SmartPointer(Person* p) : ptr(p) {}
7 ~SmartPointer() { delete ptr; }
8
9 // 重载箭头运算符
10 Person* operator->() {
11 return ptr; // 必须返回指针类型
12 }
13};
14
15int main() {
16 SmartPointer sp(new Person());
17 sp->name = "智能指针测试"; // 等价于 (sp.operator->())->name
18 sp->sayHello();
19 return 0;
20}
重载箭头运算符时:
必须是类的成员函数
必须返回指针类型或者另一个重载了箭头运算符的类对象
在多层结构下,箭头运算符的重载可以实现链式调用,这在智能指针和代理类设计中非常有用。
箭头运算符重载有几个特殊规则:
必须是类的成员函数
不能有参数(是一个无参数的一元运算符)
必须返回指针或者另一个重载了箭头运算符的对象
两层结构是指一个类重载箭头运算符,返回一个指针。
xxxxxxxxxx
291class Resource {
2public:
3 void doSomething() {
4 std::cout << "资源执行操作" << std::endl;
5 }
6 int value = 42;
7};
8
9class SmartPointer {
10private:
11 Resource* ptr;
12
13public:
14 SmartPointer(Resource* p = nullptr) : ptr(p) {}
15 ~SmartPointer() { delete ptr; }
16
17 // 箭头运算符重载 - 返回指针
18 Resource* operator->() {
19 std::cout << "箭头运算符被调用" << std::endl;
20 return ptr;
21 }
22};
23
24int main() {
25 SmartPointer sp(new Resource());
26 sp->doSomething(); // 等价于 (sp.operator->())->doSomething();
27 int x = sp->value; // 等价于 (sp.operator->())->value;
28 return 0;
29}
当编译器看到sp->doSomething()
时,它会:
调用sp.operator->()
,得到一个Resource*
指针
对该指针应用箭头运算符,访问doSomething()
方法
三层结构是指一个类重载箭头运算符,返回另一个重载了箭头运算符的对象,形成链式调用。
xxxxxxxxxx
521class Level3 {
2private:
3 Resource* ptr;
4
5public:
6 Level3(Resource* p) : ptr(p) {}
7
8 // 最终返回真正的指针
9 Resource* operator->() {
10 std::cout << "Level3::operator->被调用" << std::endl;
11 return ptr;
12 }
13};
14
15class Level2 {
16private:
17 Level3 level3;
18
19public:
20 Level2(Resource* p) : level3(p) {}
21
22 // 返回另一个重载了箭头运算符的对象
23 Level3 operator->() {
24 std::cout << "Level2::operator->被调用" << std::endl;
25 return level3;
26 }
27};
28
29class Level1 {
30private:
31 Level2 level2;
32
33public:
34 Level1(Resource* p) : level2(p) {}
35
36 // 返回另一个重载了箭头运算符的对象
37 Level2 operator->() {
38 std::cout << "Level1::operator->被调用" << std::endl;
39 return level2;
40 }
41};
42
43int main() {
44 Level1 l1(new Resource());
45 l1->doSomething();
46 // 执行顺序:
47 // 1. l1.operator->() 返回 Level2对象
48 // 2. Level2对象.operator->() 返回 Level3对象
49 // 3. Level3对象.operator->() 返回 Resource*指针
50 // 4. 使用该指针调用 doSomething()
51 return 0;
52}
执行l1->doSomething()
时,编译器会:
调用l1.operator->()
,得到一个Level2
对象
对该对象调用operator->()
,得到一个Level3
对象
对该对象调用operator->()
,得到一个Resource*
指针
对该指针应用箭头运算符,访问doSomething()
方法
1. 智能指针
xxxxxxxxxx
211template<typename T>
2class SmartPtr {
3private:
4 T* ptr;
5 int* refCount;
6
7public:
8 SmartPtr(T* p = nullptr) : ptr(p), refCount(new int(1)) {}
9 ~SmartPtr() {
10 if (--(*refCount) == 0) {
11 delete ptr;
12 delete refCount;
13 }
14 }
15
16 // 拷贝构造函数和赋值运算符省略...
17
18 T* operator->() {
19 return ptr;
20 }
21};
2. 代理模式
xxxxxxxxxx
151class DatabaseProxy {
2private:
3 Database* realDb;
4 bool hasAccess;
5
6public:
7 DatabaseProxy(Database* db, bool access) : realDb(db), hasAccess(access) {}
8
9 Database* operator->() {
10 if (!hasAccess) {
11 throw std::runtime_error("访问被拒绝");
12 }
13 return realDb;
14 }
15};
3. 延迟加载
xxxxxxxxxx
231class LazyLoader {
2private:
3 Resource* ptr;
4 std::string resourcePath;
5 bool loaded;
6
7public:
8 LazyLoader(const std::string& path) : ptr(nullptr), resourcePath(path), loaded(false) {}
9 ~LazyLoader() { delete ptr; }
10
11 Resource* operator->() {
12 if (!loaded) {
13 ptr = loadResource(resourcePath);
14 loaded = true;
15 }
16 return ptr;
17 }
18
19 Resource* loadResource(const std::string& path) {
20 // 从路径加载资源
21 return new Resource();
22 }
23};
Note
内存管理:在多层结构中,需要明确每一层的内存管理责任,避免内存泄漏。
返回值类型:链式调用中,中间层返回的是对象而非引用,可能导致性能问题。考虑返回引用以避免不必要的对象复制。
递归终止:链式调用必须最终返回一个指针,否则会导致编译错误
线程安全:在多线程环境中,需要考虑箭头运算符重载函数的线程安全性。
异常安全:箭头运算符重载函数可能抛出异常,需要确保异常安全。
xxxxxxxxxx
351template<typename T>
2class FilterIterator {
3private:
4 std::vector<T>::iterator current;
5 std::vector<T>::iterator end;
6 std::function<bool(const T&)> predicate;
7
8public:
9 FilterIterator(std::vector<T>::iterator begin,
10 std::vector<T>::iterator end,
11 std::function<bool(const T&)> pred)
12 : current(begin), end(end), predicate(pred) {
13 // 找到第一个满足条件的元素
14 while (current != end && !predicate(*current)) {
15 ++current;
16 }
17 }
18
19 T* operator->() {
20 return &(*current);
21 }
22
23 // 其他迭代器操作...
24};
25
26int main() {
27 std::vector<Resource> resources(10);
28 auto isEven = [](const Resource& r) { return r.value % 2 == 0; };
29
30 FilterIterator<Resource> it(resources.begin(), resources.end(), isEven);
31 it->doSomething(); // 只对满足条件的资源执行操作
32
33 return 0;
34}
35
函数对象是C++中一种特殊的对象,它可以像函数一样被调用。从技术上讲,函数对象是一个重载了函数调用运算符operator()
的类的实例。
函数对象是通过重载operator()
(函数调用运算符)来实现的类对象,使其行为类似于函数。
xxxxxxxxxx
171class MyFunctor {
2public:
3 // 重载函数调用运算符
4 int operator()(int x, int y) const {
5 return x + y;
6 }
7};
8
9int main() {
10 MyFunctor addObj; // 创建函数对象
11
12 // 像调用函数一样使用函数对象
13 int result = addObj(5, 3); // 调用 operator()(5, 3)
14 std::cout << "结果: " << result << std::endl; // 输出: 结果: 8
15
16 return 0;
17}
相比普通函数,函数对象有以下优势:
1. 可以保存状态
xxxxxxxxxx
271class Counter {
2private:
3 int count;
4
5public:
6 Counter() : count(0) {}
7
8 int operator()() {
9 return ++count; // 每次调用都会增加计数
10 }
11
12 void reset() {
13 count = 0;
14 }
15};
16
17int main() {
18 Counter counter;
19 std::cout << counter() << std::endl; // 输出: 1
20 std::cout << counter() << std::endl; // 输出: 2
21 std::cout << counter() << std::endl; // 输出: 3
22
23 counter.reset();
24 std::cout << counter() << std::endl; // 输出: 1
25
26 return 0;
27}
2. 可以有多个重载版本的调用运算符
xxxxxxxxxx
261class Calculator {
2public:
3 // 整数加法
4 int operator()(int a, int b) const {
5 return a + b;
6 }
7
8 // 浮点数加法
9 double operator()(double a, double b) const {
10 return a + b;
11 }
12
13 // 字符串连接
14 std::string operator()(const std::string& a, const std::string& b) const {
15 return a + b;
16 }
17};
18
19int main() {
20 Calculator calc;
21 std::cout << calc(10, 20) << std::endl; // 调用int版本
22 std::cout << calc(2.5, 3.5) << std::endl; // 调用double版本
23 std::cout << calc("Hello, ", "World!") << std::endl; // 调用string版本
24
25 return 0;
26}
3. 可以作为模板参数传递
xxxxxxxxxx
321template<typename T, typename Comparator>
2void sort(std::vector<T>& vec, Comparator comp) {
3 // 使用comp作为比较器进行排序
4 for (size_t i = 0; i < vec.size(); ++i) {
5 for (size_t j = i + 1; j < vec.size(); ++j) {
6 if (comp(vec[j], vec[i])) { // 使用函数对象进行比较
7 std::swap(vec[i], vec[j]);
8 }
9 }
10 }
11}
12
13class DescendingOrder {
14public:
15 bool operator()(int a, int b) const {
16 return a > b; // 降序排列
17 }
18};
19
20int main() {
21 std::vector<int> numbers = {5, 2, 8, 1, 9};
22
23 // 使用函数对象作为排序算法的比较器
24 sort(numbers, DescendingOrder());
25
26 // 输出排序结果
27 for (int num : numbers) {
28 std::cout << num << " ";
29 } // 输出: 9 8 5 2 1
30
31 return 0;
32}
4. 内联优化
编译器通常可以将函数对象的调用内联化,从而提高性能。
1. 一元函数对象(Unary Functor)
接受一个参数的函数对象。
xxxxxxxxxx
121class Square {
2public:
3 int operator()(int x) const {
4 return x * x;
5 }
6};
7
8int main() {
9 Square square;
10 std::cout << square(5) << std::endl; // 输出: 25
11 return 0;
12}
2. 二元函数对象(Binary Functor)
接受两个参数的函数对象。
xxxxxxxxxx
121class Multiply {
2public:
3 int operator()(int x, int y) const {
4 return x * y;
5 }
6};
7
8int main() {
9 Multiply multiply;
10 std::cout << multiply(5, 3) << std::endl; // 输出: 15
11 return 0;
12}
3. 谓词函数对象(Predicate Functor)
返回布尔值的函数对象,常用于条件判断。
xxxxxxxxxx
141class IsEven {
2public:
3 bool operator()(int x) const {
4 return x % 2 == 0;
5 }
6};
7
8int main() {
9 IsEven isEven;
10 std::cout << std::boolalpha;
11 std::cout << isEven(4) << std::endl; // 输出: true
12 std::cout << isEven(5) << std::endl; // 输出: false
13 return 0;
14}
C++标准库在<functional>
头文件中提供了许多预定义的函数对象:
1. 算术运算符
xxxxxxxxxx
201
2
3
4int main() {
5 std::plus<int> add;
6 std::minus<int> subtract;
7 std::multiplies<int> multiply;
8 std::divides<int> divide;
9 std::modulus<int> modulo;
10 std::negate<int> negate;
11
12 std::cout << add(5, 3) << std::endl; // 输出: 8
13 std::cout << subtract(5, 3) << std::endl; // 输出: 2
14 std::cout << multiply(5, 3) << std::endl; // 输出: 15
15 std::cout << divide(6, 3) << std::endl; // 输出: 2
16 std::cout << modulo(5, 3) << std::endl; // 输出: 2
17 std::cout << negate(5) << std::endl; // 输出: -5
18
19 return 0;
20}
2. 比较运算符
xxxxxxxxxx
211
2
3
4int main() {
5 std::equal_to<int> equal;
6 std::not_equal_to<int> not_equal;
7 std::greater<int> greater;
8 std::less<int> less;
9 std::greater_equal<int> greater_equal;
10 std::less_equal<int> less_equal;
11
12 std::cout << std::boolalpha;
13 std::cout << equal(5, 5) << std::endl; // 输出: true
14 std::cout << not_equal(5, 3) << std::endl; // 输出: true
15 std::cout << greater(5, 3) << std::endl; // 输出: true
16 std::cout << less(5, 3) << std::endl; // 输出: false
17 std::cout << greater_equal(5, 5) << std::endl; // 输出: true
18 std::cout << less_equal(3, 5) << std::endl; // 输出: true
19
20 return 0;
21}
3. 逻辑运算符
xxxxxxxxxx
151
2
3
4int main() {
5 std::logical_and<bool> logical_and;
6 std::logical_or<bool> logical_or;
7 std::logical_not<bool> logical_not;
8
9 std::cout << std::boolalpha;
10 std::cout << logical_and(true, false) << std::endl; // 输出: false
11 std::cout << logical_or(true, false) << std::endl; // 输出: true
12 std::cout << logical_not(true) << std::endl; // 输出: false
13
14 return 0;
15}
函数对象在STL算法中被广泛使用,特别是作为自定义比较器或转换器。
1. 排序算法
xxxxxxxxxx
181
2
3
4
5
6int main() {
7 std::vector<int> numbers = {5, 2, 8, 1, 9};
8
9 // 使用标准库函数对象进行降序排序
10 std::sort(numbers.begin(), numbers.end(), std::greater<int>());
11
12 // 输出排序结果
13 for (int num : numbers) {
14 std::cout << num << " ";
15 } // 输出: 9 8 5 2 1
16
17 return 0;
18}
2. 查找算法
xxxxxxxxxx
181
2
3
4
5
6int main() {
7 std::vector<int> numbers = {5, 2, 8, 1, 9};
8
9 // 查找大于5的第一个元素
10 auto it = std::find_if(numbers.begin(), numbers.end(),
11 [](int n) { return n > 5; });
12
13 if (it != numbers.end()) {
14 std::cout << "找到大于5的第一个元素: " << *it << std::endl;
15 }
16
17 return 0;
18}
3. 转换算法
xxxxxxxxxx
261
2
3
4
5
6class Square {
7public:
8 int operator()(int x) const {
9 return x * x;
10 }
11};
12
13int main() {
14 std::vector<int> numbers = {1, 2, 3, 4, 5};
15 std::vector<int> squares(numbers.size());
16
17 // 使用函数对象计算平方
18 std::transform(numbers.begin(), numbers.end(), squares.begin(), Square());
19
20 // 输出结果
21 for (int num : squares) {
22 std::cout << num << " ";
23 } // 输出: 1 4 9 16 25
24
25 return 0;
26}
C++11引入的Lambda表达式可以看作是函数对象的一种简化写法。
xxxxxxxxxx
261
2
3
4
5int main() {
6 std::vector<int> numbers = {5, 2, 8, 1, 9};
7
8 // 使用函数对象进行排序
9 struct {
10 bool operator()(int a, int b) const {
11 return a > b;
12 }
13 } customLess;
14
15 std::sort(numbers.begin(), numbers.end(), customLess);
16
17 // 等价的Lambda表达式
18 std::sort(numbers.begin(), numbers.end(), [](int a, int b) { return a > b; });
19
20 // 输出排序结果
21 for (int num : numbers) {
22 std::cout << num << " ";
23 } // 输出: 9 8 5 2 1
24
25 return 0;
26}
C++11引入的std::function
是一个通用的函数包装器,可以包装任何可调用对象,包括函数对象。
xxxxxxxxxx
331
2
3
4class Adder {
5private:
6 int base;
7
8public:
9 Adder(int b) : base(b) {}
10
11 int operator()(int x) const {
12 return base + x;
13 }
14};
15
16int main() {
17 // 包装函数对象
18 std::function<int(int)> add5 = Adder(5);
19
20 // 包装Lambda表达式
21 std::function<int(int)> multiply2 = [](int x) { return x * 2; };
22
23 // 包装普通函数
24 std::function<int(int)> negate = [](int x) { return -x; };
25
26 // 组合使用
27 std::cout << add5(10) << std::endl; // 输出: 15
28 std::cout << multiply2(10) << std::endl; // 输出: 20
29 std::cout << negate(10) << std::endl; // 输出: -10
30 std::cout << negate(multiply2(add5(10))) << std::endl; // 输出: -30
31
32 return 0;
33}
函数指针是C++中一种特殊类型的指针,它指向函数而不是数据。函数指针允许我们在运行时选择要调用的函数,实现回调机制和策略模式等设计模式。
函数指针的声明语法如下:
xxxxxxxxxx
11返回类型 (*指针名称)(参数类型列表);
例如,声明一个指向接受两个整数并返回整数的函数的指针:
xxxxxxxxxx
11int (*pFunc)(int, int);
1. 定义和初始化函数指针
xxxxxxxxxx
361
2
3// 定义几个具有相同签名的函数
4int add(int a, int b) {
5 return a + b;
6}
7
8int subtract(int a, int b) {
9 return a - b;
10}
11
12int multiply(int a, int b) {
13 return a * b;
14}
15
16int main() {
17 // 声明函数指针
18 int (*operation)(int, int);
19
20 // 将函数指针指向add函数
21 operation = add;
22 std::cout << "加法结果: " << operation(5, 3) << std::endl; // 输出: 8
23
24 // 将函数指针指向subtract函数
25 operation = subtract;
26 std::cout << "减法结果: " << operation(5, 3) << std::endl; // 输出: 2
27
28 // 将函数指针指向multiply函数
29 operation = multiply;
30 std::cout << "乘法结果: " << operation(5, 3) << std::endl; // 输出: 15
31
32 // 也可以直接使用函数名初始化
33 int (*anotherOperation)(int, int) = add;
34
35 return 0;
36}
2. 作为函数参数
函数指针常用作函数参数,实现回调机制:
xxxxxxxxxx
311
2
3
4// 接受函数指针作为参数的函数
5void processArray(const std::vector<int>& arr, int (*processor)(int)) {
6 for (int num : arr) {
7 std::cout << processor(num) << " ";
8 }
9 std::cout << std::endl;
10}
11
12// 可以传递给processArray的函数
13int square(int x) {
14 return x * x;
15}
16
17int cube(int x) {
18 return x * x * x;
19}
20
21int main() {
22 std::vector<int> numbers = {1, 2, 3, 4, 5};
23
24 std::cout << "平方结果: ";
25 processArray(numbers, square); // 输出: 1 4 9 16 25
26
27 std::cout << "立方结果: ";
28 processArray(numbers, cube); // 输出: 1 8 27 64 125
29
30 return 0;
31}
3. 作为函数返回值
函数也可以返回函数指针:
xxxxxxxxxx
501
2
3int add(int a, int b) {
4 return a + b;
5}
6
7int subtract(int a, int b) {
8 return a - b;
9}
10
11// 返回函数指针的函数
12int (*getOperation(char op))(int, int) {
13 if (op == '+') {
14 return add;
15 } else if (op == '-') {
16 return subtract;
17 } else {
18 return nullptr;
19 }
20}
21
22// 使用typedef简化函数指针类型
23typedef int (*Operation)(int, int);
24
25// 使用typedef后的版本
26Operation getOperationSimpler(char op) {
27 if (op == '+') {
28 return add;
29 } else if (op == '-') {
30 return subtract;
31 } else {
32 return nullptr;
33 }
34}
35
36int main() {
37 char op = '+';
38 int (*operation)(int, int) = getOperation(op);
39 if (operation) {
40 std::cout << "结果: " << operation(5, 3) << std::endl; // 输出: 8
41 }
42
43 // 使用typedef简化后的版本
44 Operation op2 = getOperationSimpler('-');
45 if (op2) {
46 std::cout << "结果: " << op2(5, 3) << std::endl; // 输出: 2
47 }
48
49 return 0;
50}
函数指针的语法可能比较复杂,可以使用typedef
或C++11的using
来简化:
xxxxxxxxxx
151// 使用typedef简化函数指针类型
2typedef int (*MathFunc)(int, int);
3
4// 使用C++11的using简化函数指针类型
5using MathOperation = int (*)(int, int);
6
7int main() {
8 MathFunc add = [](int a, int b) { return a + b; };
9 MathOperation subtract = [](int a, int b) { return a - b; };
10
11 std::cout << add(5, 3) << std::endl; // 输出: 8
12 std::cout << subtract(5, 3) << std::endl; // 输出: 2
13
14 return 0;
15}
可以创建函数指针数组,存储多个函数指针:
xxxxxxxxxx
211
2
3int add(int a, int b) { return a + b; }
4int subtract(int a, int b) { return a - b; }
5int multiply(int a, int b) { return a * b; }
6int divide(int a, int b) { return b != 0 ? a / b : 0; }
7
8int main() {
9 // 函数指针数组
10 int (*operations[4])(int, int) = {add, subtract, multiply, divide};
11
12 int a = 10, b = 5;
13 const char* opNames[] = {"加", "减", "乘", "除"};
14
15 for (int i = 0; i < 4; ++i) {
16 std::cout << a << " " << opNames[i] << " " << b << " = "
17 << operations[i](a, b) << std::endl;
18 }
19
20 return 0;
21}
C++11引入的std::function
是一个通用的函数包装器,可以存储、复制和调用任何可调用目标,包括函数指针:
xxxxxxxxxx
321
2
3
4int add(int a, int b) { return a + b; }
5
6class Multiplier {
7public:
8 int multiply(int a, int b) { return a * b; }
9};
10
11int main() {
12 // 存储普通函数
13 std::function<int(int, int)> func1 = add;
14 std::cout << func1(5, 3) << std::endl; // 输出: 8
15
16 // 存储Lambda表达式
17 std::function<int(int, int)> func2 = [](int a, int b) { return a - b; };
18 std::cout << func2(5, 3) << std::endl; // 输出: 2
19
20 // 存储成员函数
21 Multiplier multiplier;
22 std::function<int(int, int)> func3 =
23 [&multiplier](int a, int b) { return multiplier.multiply(a, b); };
24 std::cout << func3(5, 3) << std::endl; // 输出: 15
25
26 // 使用std::bind存储成员函数
27 std::function<int(int, int)> func4 =
28 std::bind(&Multiplier::multiply, multiplier, std::placeholders::_1, std::placeholders::_2);
29 std::cout << func4(5, 3) << std::endl; // 输出: 15
30
31 return 0;
32}
函数指针常用于实现回调机制,例如在事件处理中:
xxxxxxxxxx
491
2
3
4
5// 定义事件处理器类型
6typedef void (*EventHandler)(const std::string&);
7
8class Button {
9private:
10 std::string label;
11 EventHandler clickHandler;
12
13public:
14 Button(const std::string& lbl) : label(lbl), clickHandler(nullptr) {}
15
16 void setClickHandler(EventHandler handler) {
17 clickHandler = handler;
18 }
19
20 void click() {
21 if (clickHandler) {
22 clickHandler(label);
23 }
24 }
25};
26
27// 事件处理函数
28void handleButtonClick(const std::string& buttonLabel) {
29 std::cout << "按钮 '" << buttonLabel << "' 被点击了!" << std::endl;
30}
31
32void anotherHandler(const std::string& buttonLabel) {
33 std::cout << "另一个处理器: 按钮 '" << buttonLabel << "' 被点击了!" << std::endl;
34}
35
36int main() {
37 Button submitButton("提交");
38 Button cancelButton("取消");
39
40 // 设置点击处理器
41 submitButton.setClickHandler(handleButtonClick);
42 cancelButton.setClickHandler(anotherHandler);
43
44 // 模拟点击
45 submitButton.click(); // 输出: 按钮 '提交' 被点击了!
46 cancelButton.click(); // 输出: 另一个处理器: 按钮 '取消' 被点击了!
47
48 return 0;
49}
函数指针可以用于实现策略模式,允许在运行时选择算法:
xxxxxxxxxx
521
2
3
4
5// 排序策略函数
6bool ascending(int a, int b) {
7 return a < b;
8}
9
10bool descending(int a, int b) {
11 return a > b;
12}
13
14bool evenFirst(int a, int b) {
15 // 偶数优先,然后按升序
16 if (a % 2 == 0 && b % 2 != 0) return true;
17 if (a % 2 != 0 && b % 2 == 0) return false;
18 return a < b;
19}
20
21// 使用函数指针作为排序策略
22void sortVector(std::vector<int>& vec, bool (*compareFunc)(int, int)) {
23 std::sort(vec.begin(), vec.end(), compareFunc);
24}
25
26int main() {
27 std::vector<int> numbers = {5, 2, 8, 1, 9, 4, 3, 7, 6};
28
29 // 使用不同的排序策略
30 sortVector(numbers, ascending);
31 std::cout << "升序排序: ";
32 for (int num : numbers) {
33 std::cout << num << " ";
34 }
35 std::cout << std::endl;
36
37 sortVector(numbers, descending);
38 std::cout << "降序排序: ";
39 for (int num : numbers) {
40 std::cout << num << " ";
41 }
42 std::cout << std::endl;
43
44 sortVector(numbers, evenFirst);
45 std::cout << "偶数优先排序: ";
46 for (int num : numbers) {
47 std::cout << num << " ";
48 }
49 std::cout << std::endl;
50
51 return 0;
52}
成员函数指针是C++中一种特殊类型的函数指针,用于指向类的成员函数。与普通函数指针不同,成员函数指针需要考虑类的上下文,因此其语法和使用方式都更为复杂。
成员函数指针的基本声明语法如下:
xxxxxxxxxx
11返回类型 (类名::*指针名)(参数列表);
例如,声明一个指向MyClass
类中接受一个int
参数并返回double
的成员函数的指针:
xxxxxxxxxx
11double (MyClass::*pFunc)(int);
将成员函数地址赋给成员函数指针:
xxxxxxxxxx
11pFunc = &MyClass::someMethod;
注意:虽然对于普通函数指针,&
运算符是可选的,但对于成员函数指针,&
运算符是必需的。
调用成员函数指针需要一个类的实例(或指向实例的指针),使用特殊的调用运算符:
通过对象调用:(object.*pFunc)(参数)
通过指针调用:(pointer->*pFunc)(参数)
xxxxxxxxxx
321
2
3class MyClass {
4public:
5 void printValue(int value) {
6 std::cout << "Value: " << value << std::endl;
7 }
8
9 double multiply(double a, double b) {
10 return a * b;
11 }
12};
13
14int main() {
15 // 声明成员函数指针
16 void (MyClass::*printFunc)(int) = &MyClass::printValue;
17 double (MyClass::*calcFunc)(double, double) = &MyClass::multiply;
18
19 // 创建类实例
20 MyClass obj;
21 MyClass* pObj = new MyClass();
22
23 // 通过对象调用
24 (obj.*printFunc)(42);
25
26 // 通过指针调用
27 double result = (pObj->*calcFunc)(3.14, 2.0);
28 std::cout << "Result: " << result << std::endl;
29
30 delete pObj;
31 return 0;
32}
使用typedef简化语法
xxxxxxxxxx
221class MyClass {
2public:
3 void method1(int);
4 void method2(int);
5};
6
7// 使用typedef简化成员函数指针类型
8typedef void (MyClass::*MyFuncPtr)(int);
9
10// 使用using别名(C++11及以后)
11using MyFuncPtrModern = void (MyClass::*)(int);
12
13int main() {
14 MyFuncPtr fp1 = &MyClass::method1;
15 MyFuncPtrModern fp2 = &MyClass::method2;
16
17 MyClass obj;
18 (obj.*fp1)(10);
19 (obj.*fp2)(20);
20
21 return 0;
22}
1. 成员函数指针数组
xxxxxxxxxx
361
2
3
4class Calculator {
5public:
6 double add(double a, double b) { return a + b; }
7 double subtract(double a, double b) { return a - b; }
8 double multiply(double a, double b) { return a * b; }
9 double divide(double a, double b) { return b != 0 ? a / b : 0; }
10};
11
12int main() {
13 // 定义成员函数指针类型
14 typedef double (Calculator::*Operation)(double, double);
15
16 // 创建成员函数指针数组
17 Operation operations[4] = {
18 &Calculator::add,
19 &Calculator::subtract,
20 &Calculator::multiply,
21 &Calculator::divide
22 };
23
24 std::string opNames[4] = {"加法", "减法", "乘法", "除法"};
25
26 Calculator calc;
27 double a = 10.0, b = 5.0;
28
29 // 遍历并调用所有操作
30 for (int i = 0; i < 4; ++i) {
31 double result = (calc.*operations[i])(a, b);
32 std::cout << opNames[i] << ": " << result << std::endl;
33 }
34
35 return 0;
36}
2. 在类中存储成员函数指针
xxxxxxxxxx
721
2
3class Button {
4private:
5 class Handler {
6 public:
7 virtual void onClick() = 0;
8 virtual ~Handler() {}
9 };
10
11 template<class T>
12 class SpecificHandler : public Handler {
13 private:
14 T* instance;
15 void (T::*method)();
16
17 public:
18 SpecificHandler(T* instance, void (T::*method)())
19 : instance(instance), method(method) {}
20
21 void onClick() override {
22 (instance->*method)();
23 }
24 };
25
26 Handler* handler;
27
28public:
29 Button() : handler(nullptr) {}
30
31 ~Button() {
32 delete handler;
33 }
34
35 template<class T>
36 void setClickHandler(T* instance, void (T::*method)()) {
37 delete handler;
38 handler = new SpecificHandler<T>(instance, method);
39 }
40
41 void click() {
42 if (handler) {
43 handler->onClick();
44 }
45 }
46};
47
48class Application {
49public:
50 void onButtonClicked() {
51 std::cout << "按钮被点击了!" << std::endl;
52 }
53
54 void onAnotherAction() {
55 std::cout << "执行另一个动作!" << std::endl;
56 }
57};
58
59int main() {
60 Button button;
61 Application app;
62
63 // 设置点击处理函数
64 button.setClickHandler(&app, &Application::onButtonClicked);
65 button.click(); // 输出:按钮被点击了!
66
67 // 更改处理函数
68 button.setClickHandler(&app, &Application::onAnotherAction);
69 button.click(); // 输出:执行另一个动作!
70
71 return 0;
72}
3. 虚成员函数指针
xxxxxxxxxx
311
2
3class Base {
4public:
5 virtual void virtualFunc(int x) {
6 std::cout << "Base::virtualFunc(" << x << ")" << std::endl;
7 }
8};
9
10class Derived : public Base {
11public:
12 void virtualFunc(int x) override {
13 std::cout << "Derived::virtualFunc(" << x << ")" << std::endl;
14 }
15};
16
17int main() {
18 // 声明指向虚函数的成员函数指针
19 void (Base::*vptr)(int) = &Base::virtualFunc;
20
21 Base b;
22 Derived d;
23 Base* pb = &d;
24
25 // 通过不同对象调用
26 (b.*vptr)(1); // 输出:Base::virtualFunc(1)
27 (d.*vptr)(2); // 输出:Derived::virtualFunc(2)
28 (pb->*vptr)(3); // 输出:Derived::virtualFunc(3) - 多态行为!
29
30 return 0;
31}
4. 常量成员函数指针
对于const
成员函数,需要特别声明指针类型:
xxxxxxxxxx
301
2
3class MyClass {
4public:
5 void regularMethod() {
6 std::cout << "Regular method" << std::endl;
7 }
8
9 void constMethod() const {
10 std::cout << "Const method" << std::endl;
11 }
12};
13
14int main() {
15 // 普通成员函数指针
16 void (MyClass::*regular)() = &MyClass::regularMethod;
17
18 // 常量成员函数指针
19 void (MyClass::*constant)() const = &MyClass::constMethod;
20
21 MyClass obj;
22 const MyClass constObj;
23
24 (obj.*regular)(); // 正常工作
25 (obj.*constant)(); // 正常工作
26 // (constObj.*regular)(); // 编译错误:不能在const对象上调用非const方法
27 (constObj.*constant)(); // 正常工作
28
29 return 0;
30}
5. 与std::function和std::bind结合使用
在现代C++中,可以使用std::function
和std::bind
简化成员函数指针的使用:
xxxxxxxxxx
311
2
3
4class MyClass {
5public:
6 int multiply(int a, int b) {
7 return a * b;
8 }
9
10 void print(const std::string& message) {
11 std::cout << "Message: " << message << std::endl;
12 }
13};
14
15int main() {
16 MyClass obj;
17
18 // 使用std::bind创建可调用对象
19 auto multiplyBinder = std::bind(&MyClass::multiply, &obj, std::placeholders::_1, std::placeholders::_2);
20 std::cout << "Result: " << multiplyBinder(6, 7) << std::endl;
21
22 // 使用std::function存储成员函数
23 std::function<void(const std::string&)> printFunc = std::bind(&MyClass::print, &obj, std::placeholders::_1);
24 printFunc("Hello from std::function");
25
26 // C++11 lambda也可以用来封装成员函数调用
27 auto printLambda = [&obj](const std::string& msg) { obj.print(msg); };
28 printLambda("Hello from lambda");
29
30 return 0;
31}
6. 回调系统
xxxxxxxxxx
521
2
3
4
5class EventListener {
6public:
7 virtual void onEvent(const std::string& eventName) = 0;
8 virtual ~EventListener() {}
9};
10
11class EventManager {
12private:
13 std::vector<EventListener*> listeners;
14
15public:
16 void addListener(EventListener* listener) {
17 listeners.push_back(listener);
18 }
19
20 void fireEvent(const std::string& eventName) {
21 for (auto listener : listeners) {
22 listener->onEvent(eventName);
23 }
24 }
25};
26
27class Application : public EventListener {
28private:
29 std::string name;
30
31public:
32 Application(const std::string& name) : name(name) {}
33
34 void onEvent(const std::string& eventName) override {
35 std::cout << name << " 收到事件: " << eventName << std::endl;
36 }
37};
38
39int main() {
40 EventManager manager;
41
42 Application app1("应用1");
43 Application app2("应用2");
44
45 manager.addListener(&app1);
46 manager.addListener(&app2);
47
48 manager.fireEvent("系统启动");
49 manager.fireEvent("用户登录");
50
51 return 0;
52}
7. 命令模式实现
xxxxxxxxxx
801
2
3
4
5class Command {
6public:
7 virtual void execute() = 0;
8 virtual ~Command() {}
9};
10
11template<class Receiver>
12class ConcreteCommand : public Command {
13private:
14 Receiver* receiver;
15 void (Receiver::*action)();
16
17public:
18 ConcreteCommand(Receiver* r, void (Receiver::*a)())
19 : receiver(r), action(a) {}
20
21 void execute() override {
22 (receiver->*action)();
23 }
24};
25
26class Light {
27public:
28 void turnOn() {
29 std::cout << "灯已打开" << std::endl;
30 }
31
32 void turnOff() {
33 std::cout << "灯已关闭" << std::endl;
34 }
35};
36
37class Fan {
38public:
39 void start() {
40 std::cout << "风扇开始运转" << std::endl;
41 }
42
43 void stop() {
44 std::cout << "风扇已停止" << std::endl;
45 }
46};
47
48class RemoteControl {
49private:
50 std::vector<std::unique_ptr<Command>> commands;
51
52public:
53 void addCommand(std::unique_ptr<Command> cmd) {
54 commands.push_back(std::move(cmd));
55 }
56
57 void pressButton(int index) {
58 if (index >= 0 && index < commands.size()) {
59 commands[index]->execute();
60 }
61 }
62};
63
64int main() {
65 Light light;
66 Fan fan;
67 RemoteControl remote;
68
69 remote.addCommand(std::make_unique<ConcreteCommand<Light>>(&light, &Light::turnOn));
70 remote.addCommand(std::make_unique<ConcreteCommand<Light>>(&light, &Light::turnOff));
71 remote.addCommand(std::make_unique<ConcreteCommand<Fan>>(&fan, &Fan::start));
72 remote.addCommand(std::make_unique<ConcreteCommand<Fan>>(&fan, &Fan::stop));
73
74 remote.pressButton(0); // 打开灯
75 remote.pressButton(2); // 启动风扇
76 remote.pressButton(3); // 停止风扇
77 remote.pressButton(1); // 关闭灯
78
79 return 0;
80}
Note
性能考虑:成员函数指针的调用通常比普通函数指针或直接函数调用慢,因为需要额外的间接寻址。
类型安全:使用typedef
或using
定义成员函数指针类型可以提高代码可读性和类型安全性。
现代替代方案:在现代C++中,考虑使用std::function
、std::bind
或lambda表达式作为更灵活的替代方案。
多态行为:成员函数指针可以指向虚函数,并且会遵循C++的多态规则。
内存管理:在使用成员函数指针时,确保指向的对象在调用时仍然有效,避免悬垂指针问题。
调试难度:成员函数指针的语法复杂,可能导致调试困难,使用时应谨慎。
类型转换函数是一种特殊的成员函数,具有以下特点:
函数名为operator
后跟目标类型
没有显式的返回类型(返回类型隐含在函数名中)
不接受参数
通常声明为const
基本语法:
xxxxxxxxxx
11operator Type() const { /* 实现 */ }
xxxxxxxxxx
221class Seconds {
2private:
3 int value;
4
5public:
6 Seconds(int s) : value(s) {}
7
8 // 类型转换函数:将Seconds转换为int
9 operator int() const {
10 return value;
11 }
12};
13
14int main() {
15 Seconds s(60);
16 int seconds = s; // 隐式调用operator int(),seconds = 60
17
18 // 也可以显式调用
19 int explicit_seconds = static_cast<int>(s);
20
21 return 0;
22}
一个类可以定义多个类型转换函数:
xxxxxxxxxx
221class TimeSpan {
2private:
3 int seconds;
4
5public:
6 TimeSpan(int s) : seconds(s) {}
7
8 // 转换为秒
9 operator int() const {
10 return seconds;
11 }
12
13 // 转换为分钟(浮点数)
14 operator double() const {
15 return seconds / 60.0;
16 }
17
18 // 转换为布尔值(检查是否有时间)
19 operator bool() const {
20 return seconds > 0;
21 }
22};
为了防止意外的隐式转换,可以使用explicit
关键字:
xxxxxxxxxx
251class Integer {
2private:
3 int value;
4
5public:
6 Integer(int v) : value(v) {}
7
8 // 禁止隐式转换,只允许显式转换
9 explicit operator int() const {
10 return value;
11 }
12};
13
14int main() {
15 Integer i(42);
16
17 // int x = i; // 错误:不允许隐式转换
18 int y = static_cast<int>(i); // 正确:显式转换
19
20 if (static_cast<int>(i) > 40) { // 必须显式转换
21 // ...
22 }
23
24 return 0;
25}
类型转换函数也可以返回引用:
xxxxxxxxxx
121class StringWrapper {
2private:
3 std::string data;
4
5public:
6 StringWrapper(const std::string& s) : data(s) {}
7
8 // 转换为string的引用
9 operator const std::string&() const {
10 return data;
11 }
12};
可以转换为用户自定义类型:
xxxxxxxxxx
301class Meters; // 前向声明
2
3class Feet {
4private:
5 double value;
6
7public:
8 Feet(double ft) : value(ft) {}
9 double getValue() const { return value; }
10
11 // 转换为Meters类型
12 operator Meters() const;
13};
14
15class Meters {
16private:
17 double value;
18
19public:
20 Meters(double m) : value(m) {}
21 double getValue() const { return value; }
22
23 // 构造函数也可以实现从Feet到Meters的转换
24 Meters(const Feet& ft) : value(ft.getValue() * 0.3048) {}
25};
26
27// 在Feet类外部定义转换函数
28Feet::operator Meters() const {
29 return Meters(value * 0.3048);
30}
Note
类型转换函数可能导致二义性问题:
xxxxxxxxxx
241class Number {
2private:
3 int value;
4
5public:
6 Number(int v) : value(v) {}
7
8 operator int() const { return value; }
9 operator double() const { return static_cast<double>(value); }
10};
11
12void func(int i) { /* ... */ }
13void func(double d) { /* ... */ }
14
15int main() {
16 Number n(42);
17
18 // func(n); // 错误:调用不明确,可以转换为int或double
19
20 // 解决方法:显式指定转换
21 func(static_cast<int>(n));
22
23 return 0;
24}
构造函数和类型转换函数都可以实现类型转换,但方向相反:
构造函数:其他类型 → 当前类
类型转换函数:当前类 → 其他类型
xxxxxxxxxx
111class Integer {
2private:
3 int value;
4
5public:
6 // 构造函数:int → Integer
7 Integer(int v) : value(v) {}
8
9 // 类型转换函数:Integer → int
10 operator int() const { return value; }
11};
Tip
只在有明确语义的情况下使用类型转换函数
对可能导致数据丢失的转换使用explicit
避免定义过多的类型转换函数,以减少二义性
确保转换的行为符合直觉
考虑使用命名函数作为替代(如toInt()
、toString()
等)
嵌套类是在另一个类内部定义的类。嵌套类是外部类的成员,可以访问外部类的私有和保护成员(在某些条件下)。嵌套类提供了更好的封装性和逻辑组织。
xxxxxxxxxx
251class OuterClass {
2private:
3 int outerData;
4
5public:
6 // 嵌套类定义
7 class InnerClass {
8 private:
9 int innerData;
10
11 public:
12 InnerClass(int data) : innerData(data) {}
13
14 void display() {
15 std::cout << "Inner data: " << innerData << std::endl;
16 }
17 };
18
19 OuterClass(int data) : outerData(data) {}
20
21 void createInner() {
22 InnerClass inner(100);
23 inner.display();
24 }
25};
xxxxxxxxxx
521class OuterClass {
2private:
3 int privateData = 10;
4
5protected:
6 int protectedData = 20;
7
8public:
9 int publicData = 30;
10
11 // 公有嵌套类
12 class PublicInner {
13 public:
14 void accessOuter(OuterClass& outer) {
15 // 嵌套类可以访问外部类的所有成员
16 std::cout << "Private: " << outer.privateData << std::endl;
17 std::cout << "Protected: " << outer.protectedData << std::endl;
18 std::cout << "Public: " << outer.publicData << std::endl;
19 }
20 };
21
22private:
23 // 私有嵌套类
24 class PrivateInner {
25 public:
26 void doSomething() {
27 std::cout << "Private inner class method" << std::endl;
28 }
29 };
30
31public:
32 void usePrivateInner() {
33 PrivateInner inner;
34 inner.doSomething();
35 }
36};
37
38int main() {
39 OuterClass outer(0);
40
41 // 可以创建公有嵌套类的实例
42 OuterClass::PublicInner publicInner;
43 publicInner.accessOuter(outer);
44
45 // 不能直接创建私有嵌套类的实例
46 // OuterClass::PrivateInner privateInner; // 编译错误
47
48 // 但可以通过外部类的方法间接使用
49 outer.usePrivateInner();
50
51 return 0;
52}
作用域和命名
xxxxxxxxxx
291class OuterClass {
2public:
3 class InnerClass {
4 public:
5 void method() {
6 std::cout << "InnerClass method" << std::endl;
7 }
8
9 // 嵌套类中的嵌套类
10 class DeeplyNested {
11 public:
12 void deepMethod() {
13 std::cout << "Deeply nested method" << std::endl;
14 }
15 };
16 };
17};
18
19int main() {
20 // 使用作用域解析运算符访问嵌套类
21 OuterClass::InnerClass inner;
22 inner.method();
23
24 // 访问更深层的嵌套类
25 OuterClass::InnerClass::DeeplyNested deep;
26 deep.deepMethod();
27
28 return 0;
29}
前向声明
xxxxxxxxxx
241class OuterClass {
2public:
3 // 前向声明嵌套类
4 class InnerClass;
5
6 void useInner(InnerClass* inner);
7
8 // 实际定义可以在后面
9 class InnerClass {
10 private:
11 int data;
12
13 public:
14 InnerClass(int d) : data(d) {}
15 int getData() const { return data; }
16 };
17};
18
19// 在类外定义成员函数
20void OuterClass::useInner(InnerClass* inner) {
21 if (inner) {
22 std::cout << "Inner data: " << inner->getData() << std::endl;
23 }
24}
xxxxxxxxxx
621
2
3
4template<typename T>
5class MyContainer {
6private:
7 std::vector<T> data;
8
9public:
10 void add(const T& item) {
11 data.push_back(item);
12 }
13
14 // 嵌套迭代器类
15 class Iterator {
16 private:
17 typename std::vector<T>::iterator it;
18
19 public:
20 Iterator(typename std::vector<T>::iterator iter) : it(iter) {}
21
22 T& operator*() {
23 return *it;
24 }
25
26 Iterator& operator++() {
27 ++it;
28 return *this;
29 }
30
31 bool operator!=(const Iterator& other) const {
32 return it != other.it;
33 }
34
35 bool operator==(const Iterator& other) const {
36 return it == other.it;
37 }
38 };
39
40 Iterator begin() {
41 return Iterator(data.begin());
42 }
43
44 Iterator end() {
45 return Iterator(data.end());
46 }
47};
48
49int main() {
50 MyContainer<int> container;
51 container.add(1);
52 container.add(2);
53 container.add(3);
54
55 // 使用自定义迭代器
56 for (auto it = container.begin(); it != container.end(); ++it) {
57 std::cout << *it << " ";
58 }
59 std::cout << std::endl;
60
61 return 0;
62}
xxxxxxxxxx
621
2
3
4class StateMachine {
5private:
6 // 抽象状态基类
7 class State {
8 public:
9 virtual void handle(StateMachine* context) = 0;
10 virtual ~State() {}
11 };
12
13 // 具体状态类
14 class StateA : public State {
15 public:
16 void handle(StateMachine* context) override {
17 std::cout << "处理状态A,转换到状态B" << std::endl;
18 context->setState(std::make_unique<StateB>());
19 }
20 };
21
22 class StateB : public State {
23 public:
24 void handle(StateMachine* context) override {
25 std::cout << "处理状态B,转换到状态C" << std::endl;
26 context->setState(std::make_unique<StateC>());
27 }
28 };
29
30 class StateC : public State {
31 public:
32 void handle(StateMachine* context) override {
33 std::cout << "处理状态C,转换到状态A" << std::endl;
34 context->setState(std::make_unique<StateA>());
35 }
36 };
37
38 std::unique_ptr<State> currentState;
39
40public:
41 StateMachine() : currentState(std::make_unique<StateA>()) {}
42
43 void setState(std::unique_ptr<State> newState) {
44 currentState = std::move(newState);
45 }
46
47 void request() {
48 if (currentState) {
49 currentState->handle(this);
50 }
51 }
52};
53
54int main() {
55 StateMachine machine;
56
57 for (int i = 0; i < 5; ++i) {
58 machine.request();
59 }
60
61 return 0;
62}
xxxxxxxxxx
681
2
3
4class Computer {
5private:
6 std::string cpu;
7 std::string memory;
8 std::string storage;
9 std::string graphics;
10
11public:
12 // 嵌套建造者类
13 class Builder {
14 private:
15 Computer computer;
16
17 public:
18 Builder& setCPU(const std::string& cpu) {
19 computer.cpu = cpu;
20 return *this;
21 }
22
23 Builder& setMemory(const std::string& memory) {
24 computer.memory = memory;
25 return *this;
26 }
27
28 Builder& setStorage(const std::string& storage) {
29 computer.storage = storage;
30 return *this;
31 }
32
33 Builder& setGraphics(const std::string& graphics) {
34 computer.graphics = graphics;
35 return *this;
36 }
37
38 Computer build() {
39 return computer;
40 }
41 };
42
43 void display() const {
44 std::cout << "Computer Configuration:" << std::endl;
45 std::cout << "CPU: " << cpu << std::endl;
46 std::cout << "Memory: " << memory << std::endl;
47 std::cout << "Storage: " << storage << std::endl;
48 std::cout << "Graphics: " << graphics << std::endl;
49 }
50
51 // 静态方法返回建造者
52 static Builder builder() {
53 return Builder();
54 }
55};
56
57int main() {
58 Computer computer = Computer::builder()
59 .setCPU("Intel i7")
60 .setMemory("16GB DDR4")
61 .setStorage("1TB SSD")
62 .setGraphics("NVIDIA RTX 3080")
63 .build();
64
65 computer.display();
66
67 return 0;
68}
访问外部类成员
xxxxxxxxxx
471class OuterClass {
2private:
3 int privateValue = 100;
4 static int staticValue;
5
6public:
7 class InnerClass {
8 public:
9 void accessOuter() {
10 // 访问静态成员不需要外部类实例
11 std::cout << "Static value: " << staticValue << std::endl;
12
13 // 访问非静态成员需要外部类实例
14 // std::cout << privateValue << std::endl; // 编译错误
15 }
16
17 void accessOuter(OuterClass& outer) {
18 // 通过外部类实例访问私有成员
19 std::cout << "Private value: " << outer.privateValue << std::endl;
20 }
21
22 void accessOuter(OuterClass* outer) {
23 if (outer) {
24 std::cout << "Private value: " << outer->privateValue << std::endl;
25 }
26 }
27 };
28
29 void createInner() {
30 InnerClass inner;
31 inner.accessOuter(*this); // 传递当前对象
32 }
33};
34
35// 静态成员定义
36int OuterClass::staticValue = 200;
37
38int main() {
39 OuterClass outer;
40 outer.createInner();
41
42 OuterClass::InnerClass inner;
43 inner.accessOuter();
44 inner.accessOuter(outer);
45
46 return 0;
47}
友元关系
xxxxxxxxxx
251class OuterClass {
2private:
3 int secretData = 42;
4
5 // 嵌套类自动是外部类的友元
6 class InnerClass {
7 public:
8 void revealSecret(const OuterClass& outer) {
9 std::cout << "Secret: " << outer.secretData << std::endl;
10 }
11 };
12
13public:
14 InnerClass getInner() {
15 return InnerClass();
16 }
17};
18
19int main() {
20 OuterClass outer;
21 auto inner = outer.getInner();
22 inner.revealSecret(outer);
23
24 return 0;
25}
xxxxxxxxxx
451template<typename T>
2class OuterTemplate {
3private:
4 T data;
5
6public:
7 OuterTemplate(const T& d) : data(d) {}
8
9 // 模板嵌套类
10 template<typename U>
11 class InnerTemplate {
12 private:
13 U innerData;
14
15 public:
16 InnerTemplate(const U& d) : innerData(d) {}
17
18 void display(const OuterTemplate<T>& outer) {
19 std::cout << "Outer data: " << outer.data << std::endl;
20 std::cout << "Inner data: " << innerData << std::endl;
21 }
22 };
23
24 // 非模板嵌套类
25 class SimpleInner {
26 public:
27 void show(const OuterTemplate<T>& outer) {
28 std::cout << "Outer template data: " << outer.data << std::endl;
29 }
30 };
31};
32
33int main() {
34 OuterTemplate<int> outer(100);
35
36 // 使用模板嵌套类
37 OuterTemplate<int>::InnerTemplate<std::string> inner("Hello");
38 inner.display(outer);
39
40 // 使用非模板嵌套类
41 OuterTemplate<int>::SimpleInner simple;
42 simple.show(outer);
43
44 return 0;
45}
避免过度嵌套
xxxxxxxxxx
251// 不推荐:过度嵌套
2class Level1 {
3public:
4 class Level2 {
5 public:
6 class Level3 {
7 public:
8 class Level4 {
9 // 过度嵌套,难以维护
10 };
11 };
12 };
13};
14
15// 推荐:适度嵌套,清晰的逻辑关系
16class Container {
17public:
18 class Iterator {
19 // 逻辑上属于Container的迭代器
20 };
21
22 class Node {
23 // 逻辑上属于Container的节点
24 };
25};
合理使用访问控制
xxxxxxxxxx
191class WellDesigned {
2private:
3 // 实现细节的嵌套类设为私有
4 class Implementation {
5 // 外部不需要知道的实现细节
6 };
7
8public:
9 // 外部需要使用的嵌套类设为公有
10 class PublicInterface {
11 // 外部可以使用的接口
12 };
13
14protected:
15 // 派生类可能需要的嵌套类设为保护
16 class ProtectedHelper {
17 // 派生类可能需要的辅助类
18 };
19};
xxxxxxxxxx
341class Singleton {
2public:
3 static Singleton *getInstance() {
4 if (_instance == nullptr) {
5 return new Singleton();
6 }
7 return _instance;
8 }
9 friend class AutoRelease;
10
11private:
12 Singleton() : _single(0) {}
13 Singleton(const Singleton &rhs) = delete;
14 Singleton &operator=(const Singleton &rhs) = delete;
15 int _single;
16 static Singleton *_instance;
17};
18
19Singleton *Singleton::_instance = nullptr;
20
21class AutoRelease {
22public:
23 AutoRelease(Singleton *p) : _pS(p) {}
24 ~AutoRelease() {
25 if (_pS) {
26 delete _pS;
27 _pS = nullptr;
28 Singleton::_instance = nullptr;
29 }
30 }
31
32private:
33 Singleton *_pS;
34};
xxxxxxxxxx
271class Singleton {
2public:
3 static Singleton *getInstance() {
4 if (_instance == nullptr) {
5 return new Singleton();
6 }
7 return _instance;
8 }
9
10private:
11 class Destructor {
12 ~Destructor() {
13 if (Singleton::_instance) {
14 delete _instance;
15 }
16 }
17 };
18 Singleton() : _single(0) {}
19 Singleton(const Singleton &rhs) = delete;
20 Singleton &operator=(const Singleton &rhs) = delete;
21 int _single;
22 static Singleton *_instance;
23 static Destructor destructor;
24};
25
26Singleton *Singleton::_instance = nullptr;
27Singleton::Destructor Singleton::destructor;
xxxxxxxxxx
241class Singleton {
2public:
3 static Singleton *getInstance() {
4 if (_instance == nullptr) {
5 atexit(&destroyInstance);
6 return new Singleton();
7 }
8 return _instance;
9 }
10 static void destroyInstance() {
11 if (_instance) {
12 delete _instance;
13 }
14 }
15
16private:
17 Singleton() : _single(0) {}
18 Singleton(const Singleton &rhs) = delete;
19 Singleton &operator=(const Singleton &rhs) = delete;
20 int _single;
21 static Singleton *_instance;
22};
23
24Singleton *Singleton::_instance = nullptr;
xxxxxxxxxx
271class Singleton {
2public:
3 static Singleton *getInstance() {
4 pthread_once(&onceControl, &initRoutine);
5 return _instance;
6 }
7 static void destroyInstance() {
8 if (_instance) {
9 delete _instance;
10 }
11 }
12
13private:
14 Singleton() : _single(0) {}
15 Singleton(const Singleton &rhs) = delete;
16 Singleton &operator=(const Singleton &rhs) = delete;
17 static void initRoutine() {
18 _instance = new Singleton();
19 atexit(&destroyInstance);
20 }
21 int _single;
22 static Singleton *_instance;
23 static pthread_once_t onceControl;
24};
25
26Singleton *Singleton::_instance = nullptr;
27pthread_once_t Singleton::onceControl = PTHREAD_ONCE_INIT;
std::unique_ptr
xxxxxxxxxx
471
2
3
4class Singleton {
5private:
6 static std::unique_ptr<Singleton> instance;
7 static std::once_flag initFlag;
8
9 Singleton() {
10 std::cout << "Singleton 构造函数被调用" << std::endl;
11 }
12
13public:
14 ~Singleton() {
15 std::cout << "Singleton 析构函数被调用" << std::endl;
16 }
17
18 // 禁用拷贝构造和赋值操作
19 Singleton(const Singleton&) = delete;
20 Singleton& operator=(const Singleton&) = delete;
21
22 static Singleton& getInstance() {
23 std::call_once(initFlag, []() {
24 instance = std::unique_ptr<Singleton>(new Singleton());
25 });
26 return *instance;
27 }
28
29 void doSomething() {
30 std::cout << "执行某些操作" << std::endl;
31 }
32};
33
34// 静态成员定义
35std::unique_ptr<Singleton> Singleton::instance = nullptr;
36std::once_flag Singleton::initFlag;
37
38int main() {
39 Singleton& s1 = Singleton::getInstance();
40 s1.doSomething();
41
42 Singleton& s2 = Singleton::getInstance();
43 s2.doSomething();
44
45 // 程序结束时,unique_ptr 会自动释放对象
46 return 0;
47}
std::shared_ptr
xxxxxxxxxx
481
2
3
4
5class Singleton {
6private:
7 static std::shared_ptr<Singleton> instance;
8 static std::mutex mtx;
9
10 Singleton() {
11 std::cout << "Singleton 构造函数被调用" << std::endl;
12 }
13
14public:
15 ~Singleton() {
16 std::cout << "Singleton 析构函数被调用" << std::endl;
17 }
18
19 Singleton(const Singleton&) = delete;
20 Singleton& operator=(const Singleton&) = delete;
21
22 static std::shared_ptr<Singleton> getInstance() {
23 std::lock_guard<std::mutex> lock(mtx);
24 if (!instance) {
25 // 使用 make_shared 无法访问私有构造函数,所以使用这种方式
26 instance = std::shared_ptr<Singleton>(new Singleton());
27 }
28 return instance;
29 }
30
31 void doSomething() {
32 std::cout << "执行某些操作" << std::endl;
33 }
34};
35
36std::shared_ptr<Singleton> Singleton::instance = nullptr;
37std::mutex Singleton::mtx;
38
39int main() {
40 auto s1 = Singleton::getInstance();
41 s1->doSomething();
42
43 auto s2 = Singleton::getInstance();
44 s2->doSomething();
45
46 // shared_ptr 会在引用计数为0时自动释放对象
47 return 0;
48}
利用C++11的线程安全静态局部变量特性:
xxxxxxxxxx
381
2
3class Singleton {
4private:
5 Singleton() {
6 std::cout << "Singleton 构造函数被调用" << std::endl;
7 }
8
9public:
10 ~Singleton() {
11 std::cout << "Singleton 析构函数被调用" << std::endl;
12 }
13
14 // 禁用拷贝构造和赋值操作
15 Singleton(const Singleton&) = delete;
16 Singleton& operator=(const Singleton&) = delete;
17
18 static Singleton& getInstance() {
19 // C++11保证静态局部变量的线程安全初始化
20 static Singleton instance;
21 return instance;
22 }
23
24 void doSomething() {
25 std::cout << "执行某些操作" << std::endl;
26 }
27};
28
29int main() {
30 Singleton& s1 = Singleton::getInstance();
31 s1.doSomething();
32
33 Singleton& s2 = Singleton::getInstance();
34 s2.doSomething();
35
36 // 程序结束时,静态对象会自动调用析构函数
37 return 0;
38}
xxxxxxxxxx
481
2
3
4class Singleton {
5private:
6 static std::unique_ptr<Singleton, void(*)(Singleton*)> instance;
7 static std::once_flag initFlag;
8
9 Singleton() {
10 std::cout << "Singleton 构造函数被调用" << std::endl;
11 }
12
13 // 自定义删除器
14 static void deleter(Singleton* ptr) {
15 std::cout << "自定义删除器被调用" << std::endl;
16 delete ptr;
17 }
18
19public:
20 ~Singleton() {
21 std::cout << "Singleton 析构函数被调用" << std::endl;
22 }
23
24 Singleton(const Singleton&) = delete;
25 Singleton& operator=(const Singleton&) = delete;
26
27 static Singleton& getInstance() {
28 std::call_once(initFlag, []() {
29 instance = std::unique_ptr<Singleton, void(*)(Singleton*)>(
30 new Singleton(), deleter);
31 });
32 return *instance;
33 }
34
35 void doSomething() {
36 std::cout << "执行某些操作" << std::endl;
37 }
38};
39
40std::unique_ptr<Singleton, void(*)(Singleton*)> Singleton::instance{nullptr, Singleton::deleter};
41std::once_flag Singleton::initFlag;
42
43int main() {
44 Singleton& s = Singleton::getInstance();
45 s.doSomething();
46
47 return 0;
48}
xxxxxxxxxx
451
2
3
4
5template<typename T>
6class SingletonBase {
7protected:
8 SingletonBase() = default;
9 virtual ~SingletonBase() = default;
10
11public:
12 SingletonBase(const SingletonBase&) = delete;
13 SingletonBase& operator=(const SingletonBase&) = delete;
14
15 static T& getInstance() {
16 static T instance;
17 return instance;
18 }
19};
20
21// 具体的单例类
22class MyService : public SingletonBase<MyService> {
23friend class SingletonBase<MyService>;
24
25private:
26 MyService() {
27 std::cout << "MyService 构造函数被调用" << std::endl;
28 }
29
30public:
31 ~MyService() {
32 std::cout << "MyService 析构函数被调用" << std::endl;
33 }
34
35 void performService() {
36 std::cout << "执行服务操作" << std::endl;
37 }
38};
39
40int main() {
41 MyService& service = MyService::getInstance();
42 service.performService();
43
44 return 0;
45}
std::string
是C++标准库中最常用的字符串类,其底层实现经历了多个版本的演进。
xxxxxxxxxx
91class basic_string {
2private:
3 char* data_; // 指向字符数据的指针
4 size_t size_; // 当前字符串长度
5 size_t capacity_; // 分配的容量
6
7public:
8 // 构造函数、析构函数等
9};
现代C++标准库实现通常采用以下三种策略之一。
这是目前最流行的优化策略,用于避免小字符串的动态内存分配:
xxxxxxxxxx
311class string {
2private:
3 static constexpr size_t SSO_SIZE = 15; // 小字符串优化大小
4
5 union {
6 struct {
7 char* ptr; // 长字符串时指向堆内存
8 size_t size;
9 size_t capacity;
10 } long_string;
11
12 struct {
13 char buffer[SSO_SIZE + 1]; // 短字符串直接存储
14 unsigned char size; // 最高位用作标志位
15 } short_string;
16 } data_;
17
18public:
19 bool is_short() const {
20 // 检查标志位判断是否为短字符串
21 return (data_.short_string.size & 0x80) == 0;
22 }
23
24 const char* c_str() const {
25 return is_short() ? data_.short_string.buffer : data_.long_string.ptr;
26 }
27
28 size_t size() const {
29 return is_short() ? (data_.short_string.size & 0x7F) : data_.long_string.size;
30 }
31};
SSO的工作原理
xxxxxxxxxx
171
2
3
4void demonstrate_sso() {
5 // 短字符串(通常 <= 15字符)- 使用栈内存
6 std::string short_str = "Hello";
7 std::cout << "短字符串地址: " << (void*)short_str.c_str() << std::endl;
8 std::cout << "string对象地址: " << (void*)&short_str << std::endl;
9
10 // 长字符串 - 使用堆内存
11 std::string long_str = "This is a very long string that exceeds SSO limit";
12 std::cout << "长字符串地址: " << (void*)long_str.c_str() << std::endl;
13 std::cout << "string对象地址: " << (void*)&long_str << std::endl;
14
15 // 可以看到短字符串的数据地址通常接近对象地址
16 // 而长字符串的数据地址在堆上,与对象地址相差较远
17}
这是较老的实现策略,现在已不常用(C++11后基本废弃):
xxxxxxxxxx
441class cow_string {
2private:
3 struct StringRep {
4 size_t ref_count; // 引用计数
5 size_t size;
6 size_t capacity;
7 char data[1]; // 柔性数组成员
8
9 static StringRep* create(size_t capacity) {
10 StringRep* rep = (StringRep*)malloc(sizeof(StringRep) + capacity);
11 rep->ref_count = 1;
12 rep->size = 0;
13 rep->capacity = capacity;
14 return rep;
15 }
16
17 void add_ref() { ++ref_count; }
18
19 void release() {
20 if (--ref_count == 0) {
21 free(this);
22 }
23 }
24 };
25
26 StringRep* rep_;
27
28public:
29 cow_string(const cow_string& other) : rep_(other.rep_) {
30 rep_->add_ref(); // 共享数据
31 }
32
33 char& operator[](size_t index) {
34 if (rep_->ref_count > 1) {
35 // 写时复制
36 StringRep* new_rep = StringRep::create(rep_->capacity);
37 memcpy(new_rep->data, rep_->data, rep_->size);
38 new_rep->size = rep_->size;
39 rep_->release();
40 rep_ = new_rep;
41 }
42 return rep_->data[index];
43 }
44};
xxxxxxxxxx
1461
2
3
4
5class MyString {
6private:
7 static constexpr size_t SSO_CAPACITY = 15;
8
9 union {
10 struct {
11 char* ptr;
12 size_t size;
13 size_t capacity;
14 } heap_data;
15
16 struct {
17 char buffer[SSO_CAPACITY + 1];
18 unsigned char size;
19 } stack_data;
20 };
21
22 bool is_sso() const {
23 return (stack_data.size & 0x80) == 0;
24 }
25
26 void set_sso_size(size_t sz) {
27 stack_data.size = static_cast<unsigned char>(sz);
28 }
29
30 void set_heap_size(size_t sz) {
31 heap_data.size = sz;
32 stack_data.size = 0x80; // 设置标志位
33 }
34
35public:
36 MyString() {
37 stack_data.buffer[0] = '\0';
38 set_sso_size(0);
39 }
40
41 MyString(const char* str) {
42 size_t len = strlen(str);
43
44 if (len <= SSO_CAPACITY) {
45 // 使用SSO
46 memcpy(stack_data.buffer, str, len + 1);
47 set_sso_size(len);
48 } else {
49 // 使用堆分配
50 heap_data.capacity = len + 1;
51 heap_data.ptr = new char[heap_data.capacity];
52 memcpy(heap_data.ptr, str, len + 1);
53 set_heap_size(len);
54 }
55 }
56
57 MyString(const MyString& other) {
58 if (other.is_sso()) {
59 memcpy(stack_data.buffer, other.stack_data.buffer, SSO_CAPACITY + 1);
60 stack_data.size = other.stack_data.size;
61 } else {
62 size_t len = other.heap_data.size;
63 heap_data.capacity = len + 1;
64 heap_data.ptr = new char[heap_data.capacity];
65 memcpy(heap_data.ptr, other.heap_data.ptr, len + 1);
66 set_heap_size(len);
67 }
68 }
69
70 ~MyString() {
71 if (!is_sso()) {
72 delete[] heap_data.ptr;
73 }
74 }
75
76 const char* c_str() const {
77 return is_sso() ? stack_data.buffer : heap_data.ptr;
78 }
79
80 size_t size() const {
81 return is_sso() ? (stack_data.size & 0x7F) : heap_data.size;
82 }
83
84 size_t capacity() const {
85 return is_sso() ? SSO_CAPACITY : (heap_data.capacity - 1);
86 }
87
88 void reserve(size_t new_capacity) {
89 if (new_capacity <= capacity()) return;
90
91 if (is_sso() && new_capacity <= SSO_CAPACITY) return;
92
93 // 需要重新分配
94 char* new_ptr = new char[new_capacity + 1];
95 size_t current_size = size();
96 memcpy(new_ptr, c_str(), current_size + 1);
97
98 if (!is_sso()) {
99 delete[] heap_data.ptr;
100 }
101
102 heap_data.ptr = new_ptr;
103 heap_data.capacity = new_capacity + 1;
104 set_heap_size(current_size);
105 }
106
107 MyString& operator+=(const char* str) {
108 size_t str_len = strlen(str);
109 size_t current_size = size();
110 size_t new_size = current_size + str_len;
111
112 if (new_size > capacity()) {
113 reserve(std::max(new_size, capacity() * 2));
114 }
115
116 char* dest = is_sso() ? stack_data.buffer : heap_data.ptr;
117 memcpy(dest + current_size, str, str_len + 1);
118
119 if (is_sso() && new_size <= SSO_CAPACITY) {
120 set_sso_size(new_size);
121 } else {
122 if (is_sso()) {
123 // 需要从SSO转换到堆分配
124 char* new_ptr = new char[capacity() + 1];
125 memcpy(new_ptr, stack_data.buffer, new_size + 1);
126 heap_data.ptr = new_ptr;
127 heap_data.capacity = capacity() + 1;
128 }
129 set_heap_size(new_size);
130 }
131
132 return *this;
133 }
134};
135
136int main() {
137 MyString s1("Hello"); // SSO
138 std::cout << "s1: " << s1.c_str() << ", size: " << s1.size()
139 << ", capacity: " << s1.capacity() << std::endl;
140
141 MyString s2("This is a very long string that exceeds SSO"); // 堆分配
142 std::cout << "s2: " << s2.c_str() << ", size: " << s2.size()
143 << ", capacity: " << s2.capacity() << std::endl;
144
145 return 0;
146}
std::string
的底层实现经历了从简单的指针+长度+容量结构,到COW(写时复制),再到现代的SSO(小字符串优化)的演进。现代实现主要特点:
SSO优化:小字符串直接存储在对象内部,避免堆分配
联合体设计:巧妙使用union节省内存空间
标志位技巧:使用最高位区分长短字符串模式
内存对齐:优化内存访问性能
增长策略:通常采用2倍增长避免频繁重新分配
这种设计在保持接口简单的同时,大大提升了字符串操作的性能,特别是对于常见的短字符串场景。