编程C++ 开发人员

什么是 C++ 中的 'friend'? 什么时候推荐使用 friend 函数或类,以及在这方面出现了哪些安全性和设计方面的细节?

用 Hintsage AI 助手通过面试

回答

关键字 friend 允许特定的函数或其他类访问声明 friend 的类的私有和保护成员。Friend 函数可以是全局的,也可以是其他类的方法。这种构造使得需要访问类内部状态的函数能够实现,但这些函数在逻辑上与该类的接口并不相关。

建议在以下情况下使用 friend:

  • 用于实现比较运算符、数学运算符(operator<<、operator== 等),当函数必须同时访问两个对象的私有成员时。
  • 当外部函数在逻辑上不是类的方法,但需要实现其部分行为时。
  • 对于紧密合作的类之间的关系(例如,访问相邻内部对象的私有数据)。

注意:

  • 赋予 friend 函数访问权限会开放对私有数据的访问并且 破坏封装性
  • 滥用 friend 可能导致代码中 耦合度的增加 和安全性的削弱。

示例:

class Box { int width; public: Box(int w): width(w) {} friend void printWidth(const Box &b); }; void printWidth(const Box &b) { std::cout << b.width << std::endl; }

陷阱问题

问题: friend 函数可以是虚拟的吗?
常见回答: 是的,因为 friend 是函数的修饰符。
正确回答: 不,friend 函数不能是虚拟的,因为它们不是类的成员!

示例:

class Example { friend virtual void foo(); // 编译错误: virtual 不能应用于 friend };

因不懂该主题的细节而导致的真实错误示例


故事: 在设计矩阵库时,所有的算术运算符都被设为 friend 函数以加快速度,但忘记了支持常量性,过度开放了对私有成员的访问。后来出现了问题——项目中的其他函数无意中改变了 Matrix 的内部状态。



故事: 在企业系统中,助手类之间相互成为 friend 以共享对私有成员的访问。这导致了循环依赖——增加新特性需要修改所有相关类。随后的重构花费了数周时间。



故事: 为了进行封闭测试,决定将测试类设置为 production 类的 friend。当出现多个单元测试集时,跟踪哪些私有方法实际上被使用变得不可能——测试开始依赖于内部实现,这导致代码维护变得复杂。