核心要点速览
- 友元:打破封装,允许外部函数 / 类访问类的私有 / 保护成员(分友元函数、友元类、友元成员函数)
- 运算符重载:自定义类型的运算规则,不可重载 6 个运算符,支持成员函数 / 友元函数两种形式
- 特殊重载:赋值运算符=只能作为成员函数;
<</>>需作为友元函数
一、友元:打破封装的特殊访问机制
友元的核心是 “让外部实体获得类的特殊访问权限”,可访问私有(private)和保护(protected)成员,代价是削弱封装性。
1. 友元的种类
(1)友元函数
- 声明方式:类内用
friend声明,定义可在类外(非成员函数,无this指针)。
- 示例:
1 2 3 4 5 6 7 8 9 10
| class A { private: int num = 10; friend void printA(A& obj); };
void printA(A& obj) { cout << obj.num << endl; }
|
- 关键:访问类成员时需显式传递对象参数(无
this指针)。
(2)友元类
- 声明方式:类内用
friend class 类名;,目标类的所有成员函数均可访问当前类私有成员。
- 示例:
1 2 3 4 5 6 7 8 9 10 11
| class A { private: int num = 10; friend class B; }; class B { public: void accessA(A& obj) { cout << obj.num << endl; } };
|
(3)友元成员函数
- 声明方式:指定类的某个成员函数作为友元,更精准控制访问权限。
- 示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class B; class A { private: int num = 10; friend void B::show(A& obj); }; class B { public: void show(A& obj); };
void B::show(A& obj) { cout << obj.num << endl; }
|
2. 友元的特性
- 不可传递性:A 是 B 的友元,B 是 C 的友元,不代表 A 是 C 的友元。
- 单向性:A 声明 B 为友元,仅 B 能访问 A,A 不能访问 B。
- 声明位置无关:友元声明可放在类的 public/private/protected 任意区域,效果一致。
二、运算符重载:自定义类型的运算规则
运算符重载是赋予自定义类型(类 / 结构体)运算符(如+、==)的运算能力,语法为返回类型 operator运算符(参数列表)。
1. 重载规则
- 不可重载的 6 个运算符(固定):
.(成员访问)、.*(成员指针访问)、::(作用域解析)、sizeof(大小计算)、?:(三目运算符)、typeid(类型信息)。
- 不可改变的特性:运算符的优先级、结合性、操作数个数。
- 必须包含至少一个自定义类型操作数(避免重载内置类型运算)。
2. 两种重载形式
(1)成员函数重载
- 核心:左侧操作数为当前类对象(隐含
this指针),参数列表只需传入右侧操作数。
- 适用场景:左侧操作数是当前类对象(如
a + b,a 是当前类对象)。
- 示例(重载
+):
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Point { private: int x, y; public: Point(int x=0, int y=0) : x(x), y(y) {} Point operator+(const Point& rhs) { return Point(x + rhs.x, y + rhs.y); } };
Point a(1,2), b(3,4); Point c = a + b;
|
(2)友元函数重载
- 核心:无
this指针,需显式传入所有操作数(左侧 + 右侧)。
- 适用场景:左侧操作数不是当前类对象(如
cout << a,左侧是ostream对象)。
- 示例(重载
<<,输出自定义类型):
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Point { private: int x, y; public: Point(int x=0, int y=0) : x(x), y(y) {} friend ostream& operator<<(ostream& os, const Point& p) { os << "(" << p.x << "," << p.y << ")"; return os; } };
Point a(1,2); cout << a;
|
3. 特殊重载:赋值运算符=
- 规则:只能作为成员函数(编译器默认生成,执行浅拷贝)。
- 深拷贝需求:当类包含动态资源(如指针)时,需手动重写,避免双重释放。
- 示例(深拷贝赋值运算符):
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class String { private: char* str; public: String& operator=(const String& other) { if (this == &other) return *this; delete[] str; str = new char[strlen(other.str) + 1]; strcpy(str, other.str); return *this; } };
|