C/C++ 基础笔记(十二)友元、运算符重载

本篇核心知识:友元(友元函数、友元类)、运算符重载(规则、成员 / 全局重载、特殊运算符)、重载限制、前置 / 后置自增拓展


一、友元(friend)

概念

友元是 C++打破封装 的机制,允许外部函数 / 类 访问当前类的私有、保护成员 ,是单向、不可传递、不可继承的特殊关系。

特性

1. 友元函数
  • 定义:用friend声明的全局函数,不属于任何类。

  • 权限:可直接访问类的private/protected成员。

  • 特点:单向授权,不改变原函数属性,仅新增访问权限。

2. 友元类
  • 定义:用friend class 类名声明的类。

  • 权限:友元类的所有成员函数可访问当前类私有成员。

  • 特点:单向关系 、不可传递 、不可继承。

3. 友元关系规则
  • 单向:A 友元 B,B 不一定友元 A。

  • 不可传递:A 友元 B、B 友元 C,A≠友元 C。

  • 不可继承:子类不继承父类的友元关系。

  • 声明位置:可放在任意权限区(public/private/protected),不影响权限。

代码示例

1. 友元函数
复制代码
#include <iostream>
using namespace std;
​
class Beta {
private:
    int num;
public:
    Beta(int n) : num(n) {}
    // 声明全局函数为友元
    friend void up(Beta& b);
};
​
// 友元函数:访问私有成员
void up(Beta& b) {
    b.num *= 10;
    cout << b.num << endl;
}
​
int main() {
    Beta b(5);
    up(b); // 输出50
    return 0;
}
2. 友元类
复制代码
class XiaoShu {
private:
    int n;
public:
    XiaoShu(int x) : n(x) {}
    // 声明XiaoMei为友元类
    friend class XiaoMei;
};
​
class XiaoMei {
public:
    void show(XiaoShu& s) {
        cout << s.n << endl; // 访问私有成员
    }
};

相似概念比较:友元 vs 成员函数

  • 友元:外部授权,非类成员,单向访问。

  • 成员函数:类内置,默认访问私有成员,双向绑定。


二、运算符重载

概念

运算符重载是函数重载的特殊形式,为自定义类型赋予运算符新功能,语法不变、逻辑自定义。

特性

1. 重载核心规则(必考)
  • 不改变优先级、结合性、操作数个数。

  • 不创造新运算符,仅扩展已有运算符功能。

  • 不改变原有语义(如 + 不做减法)。

  • 不能重载:.、.*、::、?:、sizeof。

  • 重载形式:成员函数 、全局函数(常配合友元)。

2. 成员函数重载
  • 格式:返回值 operator运算符(参数)。

  • 特点:隐含 this 指针,第一个操作数为当前对象。

  • 适用:双目运算符(+、-、*)、单目运算符、下标[]、函数调用()、箭头->。

3. 全局函数重载
  • 格式:返回值 operator运算符(参数1, 参数2)。

  • 特点:无 this 指针,需显式传所有操作数,常声明为友元访问私有成员。

  • 适用:流运算符<</>>、单目运算符、对称双目运算符。

代码示例

1. 复数加法重载(成员函数)
复制代码
#include <iostream>
using namespace std;
​
class Complex {
private:
    double real; // 实部
    double imag; // 虚部
public:
    Complex(double r = 0, double i = 0) : real(r), imag(i) {}
    // 成员函数重载+
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }
    void show() const {
        cout << real << "+" << imag << "i" << endl;
    }
};
​
int main() {
    Complex c1(3,4), c2(1,2);
    Complex c3 = c1 + c2; // 调用重载+
    c3.show(); // 输出4+6i
    return 0;
}
2. 流运算符重载(全局 + 友元)
复制代码
class Complex {
private:
    double real, imag;
public:
    Complex(double r=0, double i=0) : real(r), imag(i) {}
    // 声明全局函数为友元
    friend ostream& operator<<(ostream& os, const Complex& c);
};
​
// 全局重载<<
ostream& operator<<(ostream& os, const Complex& c) {
    os << c.real << "+" << c.imag << "i";
    return os;
}
​
int main() {
    Complex c(2,3);
    cout << c << endl; // 输出2+3i
    return 0;
}

三、特殊运算符重载要求

1. 必须成员函数重载
  • 下标[]、函数调用()、箭头->、赋值=。

  • 原因:需通过 this 指针访问对象状态,全局无 this。

2. 必须全局函数重载
  • 流运算符<</>>、类型转换运算符。

  • 原因:左操作数为流对象(非自定义类型),无法作为 this。

3. 赋值运算符(=)
  • 必须成员重载,避免浅拷贝导致内存泄漏。

  • 默认赋值:逐字节浅拷贝,含指针时需手动深拷贝。

四、前置 / 后置自增重载(拓展)

  • 前置++x:先增后用,无额外参数,返回引用。

  • 后置x++:先用后增 ,需加int占位参数,返回值。

代码示例

复制代码
class Num {
private:
    int val;
public:
    Num(int v) : val(v) {}
    // 前置++
    Num& operator++() {
        val++;
        return *this;
    }
    // 后置++(int占位)
    Num operator++(int) {
        Num temp = *this;
        val++;
        return temp;
    }
};

拓展:重载 new/delete

  • 禁止重载全局new/delete,仅重载类专属版本。

  • 重载中不可直接调用 new/delete ,避免递归,改用malloc/free。

相关推荐
无名猿14 小时前
对象构造与析构顺序全解:声明顺序、继承链与逆序析构
c++·内存管理·调试技巧·现代c++
殷色玫瑰14 小时前
C/C++ 内存管理详解:从内存分布到 new/delete 底层原理
java·linux·c语言·c++
C++ 老炮儿的技术栈14 小时前
不一样的数值交换
数据结构·c++·人工智能·算法·c·csdn开发云
C++ 老炮儿的技术栈14 小时前
main函数之后的调用
c语言·c++·人工智能·qt·mfc·c
知识分享小能手15 小时前
C++ 学习教程,从入门到精通,C++ 友元、异常和其他特性 — 详细知识点(15)
开发语言·c++·学习
ebiobiz15 小时前
极海 APM32 使用 Nimmake 编译指南
c++·python·单片机·嵌入式硬件·mcu
朝朝辞暮i15 小时前
C++ 第 26 课:对象、指针与 ->
java·开发语言·c++
小师兄吃牛肉16 小时前
C语言指针进阶全解析
java·c语言·算法
殷色玫瑰16 小时前
C++入门基础复习:从命名空间到引用与nullptr,一篇重新捡回C++基础
java·开发语言·c++
(Charon)16 小时前
【C++面试】手写线程池:任务队列、工作线程与优雅退出
开发语言·c++