为何GCC允许嵌套类友元函数访问外部类私有成员,MSVC却不允许?
GCC与MSVC对嵌套类友元访问外部类私有成员的差异原因
这段代码能在GCC中正常编译构建,但在MSVC里会编译失败。看起来GCC允许嵌套类中的友元函数访问外部类的私有成员,而MSVC不允许,这背后的原因是什么?
template <typename T> class Outer { public: struct Inner { friend bool operator==(const Inner& a, const Inner& b) { return a.outer_.private_member_ == b.outer_.private_member_; } // 取消注释后两个编译器均能正常编译 // bool operator==(const Inner& other) { // return outer_.private_member_ == other.outer_.private_member_; // } private: Outer<T>& outer_; }; friend struct Iterator; private: int private_member_; }; bool test(Outer<int>::Inner A, Outer<int>::Inner B) { return A == B; }
原因解析
核心问题出在C++标准对嵌套类成员和友元的访问权限规定上:
- 嵌套类(这里的
Inner)属于外部类(Outer)的成员,所以嵌套类的成员函数天然有权限访问外部类的所有私有/保护成员,这也是为什么你注释掉的那版成员函数形式的operator==在两个编译器里都能正常编译的原因。 - 但友元函数不是嵌套类的成员,它只是被嵌套类授予了访问嵌套类私有成员的权限。除非外部类明确把这个友元函数也声明为自己的友元,否则它没有权限访问外部类的私有成员。
GCC在这里做了非标准的扩展,默认允许嵌套类的友元函数访问外部类的私有成员;而MSVC严格遵循了C++标准的要求,所以会编译报错。
修正方案
如果要让代码在两个编译器都能正常运行,可以选下面任意一种方式:
- 把
operator==改为Inner的成员函数(就是你注释掉的那版); - 在
Outer类中也把这个operator==声明为友元:
template <typename T> class Outer { public: struct Inner { friend bool operator==(const Inner& a, const Inner& b); // ... 其他代码 }; // 给外部类也加友元声明 friend bool operator==(const typename Outer<T>::Inner& a, const typename Outer<T>::Inner& b); // ... 其他代码 }; // 在外定义operator== template <typename T> bool operator==(const typename Outer<T>::Inner& a, const typename Outer<T>::Inner& b) { return a.outer_.private_member_ == b.outer_.private_member_; }
内容的提问来源于stack exchange,提问作者Oliver Hawker
相关产品推荐
相关产品推荐

