C++已声明友元的swap函数无法访问类私有成员问题求解
问题成因
你遇到的访问权限报错核心来自两个C++友元规则的特性:
- 友元不具备传递性,且授权是单向的:你将
Message声明为Folder的友元,仅代表Message类的成员函数有权访问Folder的私有成员;你给Message声明的swap友元,仅代表swap函数有权访问Message的私有成员。swap(Message&, Message&)本身不是Folder的友元,自然没有权限调用Folder的私有方法remMsg。 - 前置声明的可见性限制:如果仅对类做前置声明、未给出完整定义就访问其成员,编译器也会报错,因为此时编译器还不知道该类存在对应的成员。
你写的测试代码也是同样的逻辑:swap(A&, A&)不是B的友元,即便A是B的友元,swap也不能直接访问B的私有成员n。你提到删除B的前置声明就能编译通过属于异常情况,正常来说删除前置声明后A类里的std::vector<B*>会因为找不到B类型定义直接报错,大概率是你调整了类定义顺序导致的巧合。
解决方案
有两种常用的修复方案,更推荐第二种:
方案1:给Folder追加swap友元声明
直接将swap(Message&, Message&)也声明为Folder的友元即可,注意需要在Folder定义前先声明该函数:
class Folder; void swap(Message&, Message&); // 提前声明swap,让Folder能找到该函数 class Message { friend void swap(Message&, Message&); friend class Folder; // ... 原有内容 }; class Folder { friend void swap(Message&, Message&); // 新增这一行,授予swap访问权限 friend void swap(Folder&, Folder&); friend class Message; // ... 原有内容 };
方案2:封装访问逻辑到Message成员函数(更符合封装原则)
把需要访问Folder私有成员的逻辑封装为Message的私有成员函数,利用Message本身就是Folder友元的特性实现访问,不需要额外增加友元:
class Message { friend void swap(Message&, Message&); friend class Folder; public: // ... private: // 新增成员函数 void detach_from_all_folders() { for (auto f : folders) { f->remMsg(this); } } std::string contents; std::set<Folder*> folders; // ... }; // swap函数直接调用封装好的成员函数即可 void swap(Message& lhs, Message& rhs) { using std::swap; lhs.detach_from_all_folders(); rhs.detach_from_all_folders(); // ... 剩余交换逻辑 }
这个方案避免了随意扩大友元范围,代码的可维护性更好。
内容的提问来源于stack exchange,提问作者Flowerpot
相关产品推荐
相关产品推荐

