核心要点速览

  • 友元:打破封装,允许外部函数 / 类访问类的私有 / 保护成员(分友元函数、友元类、友元成员函数)
  • 运算符重载:自定义类型的运算规则,不可重载 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; // 合法:访问A的private成员
}
  • 关键:访问类成员时需显式传递对象参数(无this指针)。

(2)友元类

  • 声明方式:类内用friend class 类名;,目标类的所有成员函数均可访问当前类私有成员。
  • 示例:
1
2
3
4
5
6
7
8
9
10
11
class A {
private:
int num = 10;
friend class B; // 声明B为友元类
};
class B {
public:
void accessA(A& obj) {
cout << obj.num << endl; // 合法:B的成员函数访问A的private成员
}
};

(3)友元成员函数

  • 声明方式:指定类的某个成员函数作为友元,更精准控制访问权限。
  • 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class B; // 前置声明
class A {
private:
int num = 10;
// 声明B的show()函数为友元
friend void B::show(A& obj);
};
class B {
public:
void show(A& obj); // 成员函数声明
};
// B的show()函数定义,可访问A的private成员
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. 重载规则

  1. 不可重载的 6 个运算符(固定):
    • .(成员访问)、.*(成员指针访问)、::(作用域解析)、sizeof(大小计算)、?:(三目运算符)、typeid(类型信息)。
  2. 不可改变的特性:运算符的优先级、结合性、操作数个数。
  3. 必须包含至少一个自定义类型操作数(避免重载内置类型运算)。

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) {}
// 成员函数重载+:this指向左侧操作数
Point operator+(const Point& rhs) {
return Point(x + rhs.x, y + rhs.y);
}
};
// 调用:左侧a是this指针指向的对象
Point a(1,2), b(3,4);
Point c = a + b; // 等价于a.operator+(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) {}
// 友元函数重载<<:需访问私有成员,且左侧是ostream
friend ostream& operator<<(ostream& os, const Point& p) {
os << "(" << p.x << "," << p.y << ")";
return os; // 支持链式输出(cout << a << b)
}
};
// 调用:os=cout,p=a
Point a(1,2);
cout << a; // 等价于operator<<(cout, a),输出(1,2)

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; // 支持链式赋值(a = b = c)
}
};