全面理解C++中的friend关键字
创作时间:
作者:
@小白创作中心
全面理解C++中的friend关键字
引用
CSDN
1.
https://m.blog.csdn.net/HL_LOVE_C/article/details/145560646
在 C++ 中,friend 关键字用于授予其他类或函数访问当前类的 私有(private)和保护(protected)成员 的权限。这种机制打破了严格的封装性,但可以在特定场景下提高代码的灵活性和效率。以下是 friend 的详细说明和使用示例:
一、friend的作用
- 允许外部访问私有成员:类的私有成员通常只能被其自身的成员函数访问,但通过 friend 声明,可以授权特定的外部函数、其他类或成员函数访问这些私有成员。
- 不破坏封装性的合理场景:例如操作符重载、工具函数或紧密协作的类之间共享数据。
二、friend的用法
1. 友元函数(Friend Function)
- 定义:将非成员函数声明为友元,使其可以访问类的私有成员。
- 适用场景:操作符重载(如 <<、>>)、工具函数等。
- 示例:
#include <iostream>
class MyClass {
private:
int secret = 42;
public:
// 声明友元函数(非成员函数)
friend void printSecret(const MyClass& obj);
};
// 友元函数定义
void printSecret(const MyClass& obj) {
std::cout << "Secret: " << obj.secret << std::endl; // ✅ 允许访问私有成员
}
int main() {
MyClass obj;
printSecret(obj); // 输出 "Secret: 42"
return 0;
}
2. 友元类(Friend Class)
- 定义:将另一个类声明为友元,使其所有成员函数可以访问当前类的私有成员。
- 适用场景:两个类需要紧密协作(如迭代器与容器)。
- 示例:
class Storage {
private:
int data = 100;
public:
// 声明友元类
friend class Accessor;
};
class Accessor {
public:
static int getData(const Storage& s) {
return s.data; // ✅ 允许访问 Storage 的私有成员
}
};
int main() {
Storage s;
std::cout << Accessor::getData(s); // 输出 100
return 0;
}
3. 友元成员函数(Friend Member Function)
- 定义:将另一个类的特定成员函数声明为友元。
- 适用场景:仅允许其他类的部分函数访问私有成员。
- 示例:
class B; // 前向声明
class A {
private:
int secret = 200;
public:
// 声明 B 的成员函数为友元
friend void B::accessA(const A& a);
};
class B {
public:
void accessA(const A& a) {
std::cout << "A's secret: " << a.secret; // ✅ 允许访问
}
};
int main() {
A a;
B b;
b.accessA(a); // 输出 "A's secret: 200"
return 0;
}
三、friend的关键规则
- 单向性:友元关系是单向的。若 A 是 B 的友元,B 不自动成为 A 的友元。
- 不传递性:友元关系不传递。若 A 是 B 的友元,B 是 C 的友元,A 不自动成为 C 的友元。
- 不可继承:基类的友元不自动成为派生类的友元。
- 声明位置无关:友元声明可放在类的 public、protected 或 private 区域,效果相同。
四、典型应用场景
1. 操作符重载
- 例如重载 << 和 >> 实现自定义类的输入输出:
class MyClass {
private:
int value;
public:
MyClass(int v) : value(v) {}
// 声明友元函数以访问私有成员
friend std::ostream& operator<<(std::ostream& os, const MyClass& obj);
};
std::ostream& operator<<(std::ostream& os, const MyClass& obj) {
os << "Value: " << obj.value; // ✅ 访问私有成员
return os;
}
int main() {
MyClass obj(42);
std::cout << obj; // 输出 "Value: 42"
return 0;
}
2. 需要访问私有数据的工具函数
- 例如实现一个序列化函数:
class Data {
private:
int id;
std::string content;
public:
Data(int i, const std::string& s) : id(i), content(s) {}
friend std::string serialize(const Data& data);
};
std::string serialize(const Data& data) {
return "ID: " + std::to_string(data.id) + ", Content: " + data.content;
}
3. 紧密协作的类
- 例如容器类与迭代器:
template<typename T>
class Vector {
private:
T* data;
size_t size;
public:
friend class Iterator; // 迭代器需要访问私有成员
class Iterator {
private:
T* ptr;
public:
Iterator(T* p) : ptr(p) {}
T& operator*() { return *ptr; }
// ...
};
};
五、优缺点与最佳实践
优点
- 灵活性:支持操作符重载和特殊函数访问私有数据。
- 性能优化:避免通过公有接口间接访问数据的开销。
缺点
- 破坏封装性:过度使用会导致代码维护困难。
- 耦合性增加:友元类/函数与当前类紧密绑定。
最佳实践
- 慎用友元:优先通过公有接口访问数据,仅在必要时使用。
- 最小化友元范围:尽量声明友元函数而非友元类,或仅开放必要的成员函数。
- 文档说明:明确标注友元关系的设计意图。
总结
特性 | 说明 |
|---|---|
核心作用 | 授权外部函数或类访问私有/保护成员 |
常见用法 | 友元函数、友元类、友元成员函数 |
典型场景 | 操作符重载、工具函数、紧密协作的类 |
注意事项 | 单向性、不传递性、不可继承 |
替代方案 | 优先使用公有接口,避免过度依赖友元 |
合理使用 friend 关键字可以在不严重破坏封装性的前提下,解决特定场景下的代码设计问题。
热门推荐
未来五年,中东这个国家将是大储出海的理想目的地
AI产品经理如何推动企业AI落地:难点、策略与实战解析
入夏之前家里备点这种花,调节免疫效果好
办理手机卡需要什么证件?最全证件指南
如何高效使用语音测试方法来提升用户体验?
劳动法规定每天工作多久:标准工时制度与加班的规定
抗寄生虫药物之—青蒿素
新旧骨折大不同!如何精准诊断、治疗骨质疏松性椎体压缩骨折?
轻轨如何进行换轨操作?换轨过程中有哪些技术要点?
桑螵蛸的功效与作用 桑螵蛸怎么吃
桑螵蛸的功效与作用
潮剧《江姐》为何成现代戏经典?
咳嗽不止?从这些细节辨识身体发出的健康警报
潘承洞:治学坚韧不拔 治校追求卓越
环跳疼痛如何简单治疗
人力资源员工薪酬如何与市场水平对齐?
买到假烟怎么维护自己的权益
楪祈:《罪恶王冠》中的温柔歌姬与战士
护肝片对慢性肝炎是否有效果
从《宝可梦大集结》的"兵线",看游戏机制的外表和本质
自制冰美式咖啡完美步骤教程,冰块加咖啡豆,教你轻松制作
解放军重炮演习现场:炮火轰鸣火力全开
木瓜海棠与海棠的区别
科普:3分钟知悉急性荨麻疹能不能接种流感疫苗
科普:3分钟知悉急性荨麻疹能不能接种新冠疫苗
2024软科世界大学学术排名发布:山东13所高校上榜,全国第五
晨起后的黄金时间别浪费,改掉4个坏习惯,更能健康长寿
每天多睡1小时,3年减重12公斤!充足睡眠有助于减少热量摄入
“深耕安徽”专题系列报告之总量篇:科创引领发展,从产业视角解读安徽十年崛起
谷维素的功效与作用