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

发布于:2025-03-19 ⋅ 阅读:(19) ⋅ 点赞:(0)

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;
}

输出: 

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