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

相关推荐
赴生-1 天前
C++进阶 异常
开发语言·c++
x138702859571 天前
c语言中srtlen(指针使用计算字符长度)、传值和传址调用
c语言·开发语言·算法·visual studio
凡人叶枫1 天前
Effective C++ 条款28:避免使用 handles 指向对象内部
linux·服务器·开发语言·c++·嵌入式开发
zwenqiyu1 天前
P5283 [十二省联考 2019] 异或粽子题解
c++·学习·算法
Queenie_Charlie1 天前
哈夫曼树
数据结构·c++·哈夫曼树
lihao lihao1 天前
Linux信号
开发语言·c++·算法
大白话_NOI1 天前
【洛谷 P2249】查找(深基 13. 例 1)+ 详细分析
c++·算法
智者知已应修善业1 天前
【51单片机2个外部中断显示中断历时,初始化8左移3位共阳数码管】2024-6-6
c++·经验分享·笔记·算法·51单片机
码之气三段.1 天前
edu158-B
c++
青梅橘子皮1 天前
Linux---进程控制(2)(进程程序替换)
linux·c++·算法