当前位置: 首页 > article >正文

C++ 友元 / friend关键字解读

1.1. C++面向生活 

借助一个生活中的例子来理解友元技术: 

在生活中,你的家里有 客厅(Public)卧室(Private)

  • 客厅 是开放的,任何来访的客人都可以进入。
  • 卧室 是私密的,只有你自己能进去。
  • 但是,你可以允许你的好朋友进入你的卧室,他们不会像普通客人那样被拒之门外。

在 C++ 里,类的 私有(private)公共(public) 访问权限就类似这种关系。
如果想让类外的特定函数或类访问私有成员,就需要用到“友元(friend)”技术。
友元的作用是 让某些特殊的函数或类访问另一个类的私有成员,就像你允许好朋友进入你的卧室一样。

C++ 中的 友元(friend) 关键字提供了三种实现方式:

  1. 全局函数做友元(允许某个函数访问私有成员)
  2. 类做友元(允许某个类的所有成员函数访问私有成员)
  3. 成员函数做友元(只允许某个特定的成员函数访问私有成员)

通过友元机制,我们可以在 保持封装性的同时,灵活地控制访问权限,让特定的外部函数或类能够访问私有数据。

1.2. 全局函数做友元

friend void goodGay(Building &building); // goodGay全局函数是 Building好朋友,可以访问Building中私有成员

整体代码: 

#include<iostream>
#include<string>
typedef std::string STRING; // 为 std::string 定义一个新的类型别名 STRING。
                            // 等价于:using STRING = std::string;(C++11引入)


class Building{
    private:
    STRING m_BedRoom; // 卧室

    public:
    STRING m_SittingRoom; // 客厅

    // 构造函数
    Building(){
        m_SittingRoom="客厅";
        m_BedRoom="卧室";
    }
    friend void goodGay(Building &building); // goodGay全局函数是 Building好朋友,可以访问Building中私有成员
};

// 全局函数
void goodGay(Building &building){
    std::cout<<"好基友全局函数正在访问:"<<building.m_SittingRoom<<std::endl;
    std::cout<<"好基友全局函数正在访问:"<<building.m_BedRoom<<std::endl;
}

int main(){
    Building house1; // 实例化一个house1
    goodGay(house1);
    return 0;
}

// 输出:
// 好基友全局函数正在访问:客厅
// 好基友全局函数正在访问:卧室

1.3. 类做友元

friend class GoodGay; // GoodGay类是本类的好朋友,可以访问本类中私有成员
#include<iostream>
#include<string>
typedef std::string STRING; // 为 std::string 定义一个新的类型别名 STRING。
                            // 等价于:using STRING = std::string;(C++11引入)



class Building{
    private:
    STRING m_BedRoom; // 卧室

    public:
    STRING m_SittingRoom; // 客厅

    // 构造函数
    Building(){
        m_SittingRoom="客厅";
        m_BedRoom="卧室";
    }

    friend class GoodGay; // GoodGay类是本类的好朋友,可以访问本类中私有成员
};

class GoodGay{
    public:
    void visit(Building &building){ // 参观函数  访问Building中的属性
        std::cout<<"好基友类正在访问:"<<building.m_SittingRoom<<std::endl;
        std::cout<<"好基友类正在访问:"<<building.m_BedRoom<<std::endl;
    }
    
};

int main(){
    Building house1; // 实例化一个house1
    GoodGay gg1; // 实例化一个好基友
    gg1.visit(house1); // 好基友1访问house1中的属性【客厅、卧室】
    return 0;
}

// 输出:
// 好基友类正在访问:客厅
// 好基友类正在访问:卧室

1.4. 成员函数做友元

成员函数做友元时,我们可以只让某个特定的成员函数访问类的私有成员,而不是整个类。

语法: 

// 只让 GoodGay 类的 visit 函数访问私有成员
    friend void GoodGay::visit(Building &building);

具体看下面的代码: 

错误示例:

#include<iostream>
#include<string>
typedef std::string STRING; // 为 std::string 定义一个新的类型别名 STRING。
                            // 等价于:using STRING = std::string;(C++11引入)

class GoodGay; // 提前声明 GoodGay 类

class Building{
    private:
    STRING m_BedRoom; // 卧室

    public: 
    STRING m_SittingRoom; // 客厅

    // 构造函数
    Building(){
        m_SittingRoom="客厅";
        m_BedRoom="卧室";
    }

    // 只让 GoodGay 类的 visit 函数访问私有成员
    friend void GoodGay::visit(Building &building);
};

class GoodGay{
    public:
    void visit(Building &building){ // 参观函数  访问Building中的属性
        std::cout<<"好基友类正在访问:"<<building.m_SittingRoom<<std::endl;
        std::cout<<"好基友类正在访问:"<<building.m_BedRoom<<std::endl;
    }   
};

int main(){
    Building house1; // 实例化一个house1
    GoodGay gg1; // 实例化一个好基友
    gg1.visit(house1); // 好基友1访问house1中的属性【客厅、卧室】
    return 0;
}

 错误点:

原因: friend 关键字的使用位置不正确

问题分析

  1. GoodGay 类的定义在 Building 之后

  • 但是在 Building 里写 friend void GoodGay::visit(Building &building);,编译器此时还 不知道 GoodGay 类里有 visit 这个成员函数。
  1. 解决方案

  • 需要先 完整定义 GoodGay,然后 Building 再声明 GoodGay::visit 为友元。

 正确示例:

#include <iostream>
#include <string>

typedef std::string STRING; // 定义字符串类型别名

class Building; // 先声明 Building 类

class GoodGay {
public:
    void visit(Building &building); // 只有 visit 这个函数是友元
};

class Building {
private:
    STRING m_BedRoom; // 卧室(私有成员)

public:
    STRING m_SittingRoom; // 客厅(公有成员)

    // 构造函数
    Building() {
        m_SittingRoom = "客厅";
        m_BedRoom = "卧室";
    }

    // 只让 GoodGay 类的 visit 函数访问私有成员
    friend void GoodGay::visit(Building &building);
};

// **定义 visit 函数**
void GoodGay::visit(Building &building) { 
    std::cout << "好基友访问: " << building.m_SittingRoom << std::endl;
    std::cout << "好基友访问: " << building.m_BedRoom << std::endl; // 允许访问私有成员
}

int main() {
    Building house1; // 实例化一个 Building 对象
    GoodGay gg1; // 实例化一个 GoodGay 对象
    gg1.visit(house1); // 访问 house1 的成员变量【客厅、卧室】
    return 0;
}

输出: 

好基友类正在访问: 客厅
好基友类正在访问: 卧室


http://www.kler.cn/a/590803.html

相关文章:

  • MongoDB 只能存储能够序列化的数据(比如字符串、数字等),而 Python 的 UUID 对象并不是直接可以存入数据库的格式。
  • Centos7更换仓库源为阿里云镜像
  • Hyperlane:Rust 生态中的轻量级高性能 HTTP 服务器库,助力现代 Web 开发
  • 力扣题目汇总 使用贪心算法解决问题
  • 热更新解决方案5——toLua
  • TCP 客户端 - 服务器通信程序搭建
  • ora-600 ktugct: corruption detected---惜分飞
  • 晶艺代理,100V3.5A高耐压LA1823完全替换MP9487--启烨科技有限公司
  • 每天五分钟深度学习框架pytorch:基于pytorch搭建循环神经网络RNN
  • 【大模型基础_毛玉仁】3.1 Prompt 工程简介
  • 清晰易懂的Node.js安装教程
  • 【Git学习笔记】Git分支管理策略及其结构原理分析
  • 操作系统的心脏节拍:CPU中断如何驱动内核运转?
  • Conda 环境迁移指南
  • dataframe数据形式操作中的diff和shift函数区别与对比
  • [Lc15_bfs+floodfill] 图像渲染 | 岛屿数量 | 岛屿的最大面积 | 被围绕的区域
  • 使用 ESP8266 和 Android 应用程序实现基于 IOT 的语音控制家庭自动化
  • 从字段级脱敏到文件级授权,构建全场景数据安全闭环
  • Linux与HTTP报头属性和请求方式
  • flutter 专题 八十八 Flutter原生混合开发