友元函数可直接访问类的私有成员,包括动态数组指针及其size,但需检查空指针和有效性;声明与定义签名须严格一致;不应擅自释放内存,多线程下需配合同步机制。

友元函数能直接访问私有成员,包括动态数组指针
友元函数不是类的成员,但它被授予了和类成员函数同等的访问权限——这意味着只要类里把某个函数声明为 friend,它就能无视 private 或 protected 修饰符,直接读写所有成员,包括指向堆内存的私有指针(比如 int* data)。关键不在于“数组是不是动态的”,而在于“指针本身是否可访问”。
常见错误是以为友元只能访问值、不能解引用或操作内存。其实只要指针变量是 private 的,友元就能拿到它;后续的 data[i]、delete[] data 等操作,和在类内做完全一样。
声明友元时必须匹配函数签名,尤其注意 const 和参数类型
如果类中声明的是 friend void print(const MyClass& obj);,但你定义的是 void print(MyClass& obj)(少了 const),链接会失败,报错类似 undefined reference to 'print(MyClass&)'。编译器把带 const 和不带的视为两个不同函数。
- 声明和定义的函数名、参数类型、
const修饰必须严格一致 - 如果友元要修改对象状态,别加
const;如果只读,加上更安全 - 动态数组通常伴随
size成员,友元函数也得一并访问这个size才能安全遍历
访问动态数组时,必须同步处理 size 和内存有效性
友元函数能访问 data 指针,但不会自动知道它是否为空、是否已分配、长度多少。一旦忽略 size 或未判空,就容易触发 segmentation fault 或越界读写。
例如:
class MyClass {
private:
int* data;
size_t size;
public:
MyClass(size_t n) : size(n), data(n ? new int[n] : nullptr) {}
~MyClass() { delete[] data; }
friend void dump(const MyClass& obj);
};
<p>void dump(const MyClass& obj) {
if (!obj.data || obj.size == 0) return; // 必须检查
for (size_t i = 0; i </p><h3>友元无法绕过 delete[] / new[] 的所有权规则</h3><p>友元可以调用 <code>delete[] obj.data</code>,但这不意味着它该这么做。动态数组的生命周期应由类自己管理,友元函数通常只负责观察或临时操作。否则容易引发双重释放、悬空指针等问题。</p>
- 除非明确设计为“移交所有权”的接口(如
release_data()),否则友元不应 delete 类的私有指针 - 如果真要释放,类内应提供公有方法(如
clear()),而不是让友元直接操作 - 多线程环境下,友元对动态数组的读写必须配合类已有的同步机制(如 mutex),友元本身不自动获得线程安全
最易被忽略的一点:友元函数看到的是原始指针值,它不知道这个指针是不是刚被 move 构造转移走的——类的移动语义必须显式处理 data 和 size,否则友元可能访问到已失效的内存。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











