C++ 中,友元类(Friend Class)

在 C++ 中,友元类(Friend Class) 是一种特殊的类关系,允许一个类(友元类)访问另一个类的 私有(private)保护(protected) 成员。这种机制打破了封装性,但适用于需要紧密协作的场景。

1. 基本语法

在类定义中,使用 friend class 关键字声明友元类:

class ClassB {
private:
    int secretData;

    // 声明 ClassA 是 ClassB 的友元类
    friend class ClassA;  
};

class ClassA {
public:
    void accessSecret(ClassB& obj) {
        // 可以访问 ClassB 的私有成员 secretData
        std::cout << obj.secretData << std::endl;  
    }
};

2. 核心特性

  • 单向性:友元关系是单向的。 若 ClassA 是 ClassB 的友元,ClassA 可访问 ClassB 的私有成员,但 ClassB 不能访问 ClassA 的私有成员。
  • 不传递:友元关系不可继承或传递。 若 ClassA 是 ClassB 的友元,ClassA 的子类或友元类不会自动成为 ClassB 的友元。
  • 声明位置:友元类声明需在目标类内部,且不受 public/private 访问限定符影响。

3. 典型使用场景

场景 1:工具类辅助

  • 当需要设计一个工具类(如数据序列化类)直接操作另一个类的私有数据时。
class DataSerializer;  // 前向声明

class UserData {
private:
    int id;
    std::string name;

    friend class DataSerializer;  // 声明友元类
};

class DataSerializer {
public:
    static void serialize(const UserData& data) {
        // 直接访问 UserData 的私有成员
        std::cout << data.id << ", " << data.name << std::endl;
    }
};

场景 2:容器与迭代器

  • 容器类(如 MyVector)的迭代器类(如 Iterator)通常需要访问容器的私有成员。
class Iterator;  // 前向声明

class MyVector {
private:
    int* data;
    int size;

    friend class Iterator;  // 声明友元类
};

class Iterator {
public:
    Iterator(const MyVector& vec) : vec(vec) {}
    int getCurrent() {
        return vec.data[currentIndex];  // 访问 MyVector 的私有成员
    }
private:
    const MyVector& vec;
    int currentIndex = 0;
};

4. 注意事项

  • 谨慎使用:友元类破坏封装性,过度使用会导致代码耦合性高、维护困难。
  • 替代方案:优先考虑通过公共接口(如 getter/setter)访问私有数据。
  • 前向声明:若友元类未定义,需提前用 class ClassName; 前向声明。

5. 友元类 vs 友元函数

作用对象

整个类(所有成员函数)

单个函数

适用场景

需要多个函数访问私有成员

只需单个函数访问私有成员

声明方式

friend class ClassName;

friend void funcName(...);

6. 综合示例

#include <iostream>

// 前向声明
class Printer;

class Document {
private:
    std::string content;

    // 声明 Printer 是 Document 的友元类
    friend class Printer;  
public:
    Document(const std::string& text) : content(text) {}
};

class Printer {
public:
    void print(const Document& doc) {
        // 直接访问 Document 的私有成员 content
        std::cout << "Printing: " << doc.content << std::endl;
    }
};

int main() {
    Document doc("Secret Report");
    Printer printer;
    printer.print(doc);  // 输出 "Printing: Secret Report"
    return 0;
}

7. 总结

  • 友元类的作用:允许特定类直接访问私有和保护成员。
  • 适用场景:容器与迭代器、工具类辅助等紧密协作场景。
  • 代价:破坏封装性,需权衡设计需求与代码可维护性。
全部评论

相关推荐

头像
10-13 18:10
已编辑
东南大学 C++
。收拾收拾心情下一家吧————————————————10.12更新上面不知道怎么的,每次在手机上编辑都会只有最后一行才会显示。原本不想写凉经的,太伤感情了,但过了一天想了想,凉经的拿起来好好整理,就像象棋一样,你进步最快的时候不是你赢棋的时候,而是在输棋的时候。那废话不多说,就做个复盘吧。一面:1,经典自我介绍2,项目盘问,没啥好说的,感觉问的不是很多3,八股问的比较奇怪,他会深挖性地问一些,比如,我知道MMU,那你知不知道QMMU(记得是这个,总之就是MMU前面加一个字母)4,知不知道slab内存分配器-&gt;这个我清楚5,知不知道排序算法,排序算法一般怎么用6,写一道力扣的,最长回文子串反问:1,工作内容2,工作强度3,关于友商的问题-&gt;后面这个问题问HR去了,和中兴有关,数通这个行业和友商相关的不要提,这个行业和别的行业不同,别的行业干同一行的都是竞争关系,数通这个行业的不同企业的关系比较微妙。特别细节的问题我确实不知道,但一面没挂我。接下来是我被挂的二面,先说说我挂在哪里,技术性问题我应该没啥问题,主要是一些解决问题思路上的回答,一方面是这方面我准备的不多,另一方面是这个面试写的是“专业面试二面”,但是感觉问的问题都是一些主管面/综合面才会问的问题,就是不问技术问方法论。我以前形成的思维定式就是专业面会就是会,不会就直说不会,但事实上如果问到方法论性质的问题的话得扯一下皮,不能按照上面这个模式。刚到位置上就看到面试官叹了一口气,有一些不详的预感。我是下午1点45左右面的。1,经典自我介绍2,你是怎么完成这个项目的,分成几个步骤。我大致说了一下。你有没有觉得你的步骤里面缺了一些什么,(这里已经在引导我往他想的那个方向走了),比如你一个人的能力永远是不够的,,,我们平时会有一些组内的会议来沟通我们的所思所想。。。。3,你在项目中遇到的最困难的地方在什么方面4,说一下你知道的TCP/IP协议网络模型中的网络层有关的协议......5,接着4问,你觉得现在的socket有什么样的缺点,有什么样的优化方向?6,中间手撕了一道很简单的快慢指针的问题。大概是在链表的倒数第N个位置插入一个节点。————————————————————————————————————10.13晚更新补充一下一面说的一些奇怪的概念:1,提到了RPC2,提到了fu(第四声)拷贝,我当时说我只知道零拷贝,知道mmap,然后他说mmap是其中的一种方式,然后他问我知不知道DPDK,我说不知道,他说这个是一个高性能的拷贝方式3,MMU这个前面加了一个什么字母我这里没记,别问我了4,后面还提到了LTU,VFIO,孩子真的不会。
走呀走:华子二面可能会有场景题的,是有些开放性的问题了
点赞 评论 收藏
分享
09-21 21:14
门头沟学院
否极泰来来来来:和他说:这里不好骂你,我们加个微信聊
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务