[C++高频精进] 面向对象编程:友元与运算符重载

核心要点速览

  • 友元:打破封装,允许外部函数 / 类访问类的私有 / 保护成员(分友元函数、友元类、友元成员函数)
  • 运算符重载:自定义类型的运算规则,不可重载 6 个运算符,支持成员函数 / 友元函数两种形式
  • 特殊重载:赋值运算符=只能作为成员函数;<</>>需作为友元函数

一、友元:打破封装的特殊访问机制

友元的核心是 “让外部实体获得类的特殊访问权限”,可访问私有(private)和保护(protected)成员,代价是削弱封装性。

1. 友元的种类

(1)友元函数
  • 声明方式:类内用friend声明,定义可在类外(非成员函数,无this指针)。

  • 示例:

    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 类名;,目标类的所有成员函数均可访问当前类私有成员。
  • 示例:
    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)友元成员函数
  • 声明方式:指定类的某个成员函数作为友元,更精准控制访问权限。
  • 示例:
    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 是当前类对象)。
  • 示例(重载+):
    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对象)。
  • 示例(重载<<,输出自定义类型):
    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. 特殊重载:赋值运算符=

  • 规则:只能作为成员函数(编译器默认生成,执行浅拷贝)。
  • 深拷贝需求:当类包含动态资源(如指针)时,需手动重写,避免双重释放。
  • 示例(深拷贝赋值运算符):
    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)
        }
    };
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值