C++模板类的模板友元显式实例化访问私有成员报错问题
问题描述
现有两个以int非类型模板参数dim参数化的模板类:
MainClass:存在私有成员变量,需要授予同dim参数的FriendClass友元访问权限FriendClass:需要访问MainClass对应实例的私有成员
两个类分别存放在独立的头文件、源文件中,属于不同翻译单元,为避免循环依赖,原本在MainClass内部前向声明了模板形式的FriendClass,并在两个类的源文件末尾对dim=2、dim=3版本做了显式实例化。但编译时触发错误:FriendClass的方法访问MainClass私有成员时,编译器提示成员为私有属性无法访问。
原始代码如下:
MainClass.hpp
#ifndef MAIN_CLASS_HPP #define MAIN_CLASS_HPP template <int dim> class MainClass { public: MainClass(){}; private: template <int friend_dim> class FriendClass; friend class FriendClass<dim>; double private_member = 3.0; }; #endif
MainClass.cpp
#include "MainClass.hpp" template class MainClass<2>; template class MainClass<3>;
FriendClass.hpp
#ifndef FRIEND_CLASS_CPP #define FRIEND_CLASS_CPP #include "MainClass.hpp" template <int dim> class FriendClass { public: FriendClass(){}; void print_main_class(MainClass<dim> &main_class); }; #endif
FriendClass.cpp
#include "FriendClass.hpp" #include <iostream> template <int dim> void FriendClass<dim>::print_main_class(MainClass<dim> &main_class) { std::cout << main_class.private_member << std::endl; } template class FriendClass<2>; template class FriendClass<3>;
main.cpp
#include "MainClass.hpp" #include "FriendClass.hpp" int main() { const int dim = 2; MainClass<dim> main_class; FriendClass<dim> friend_class; friend_class.print_main_class(main_class); return 0; }
问题根因
错误的核心是*FriendClass的前向声明位置错误*:
在MainClass的类内部、private作用域下写的template <int friend_dim> class FriendClass;,声明的是*MainClass作用域下的内嵌模板类*,而非全局作用域定义的那个FriendClass。后续的友元声明实际上把权限授予了这个根本没有实现的内嵌类,全局的FriendClass自然拿不到MainClass私有成员的访问权限。
修复方案
只需要修改MainClass.hpp,把FriendClass的前向声明移到全局作用域、MainClass定义之前即可,不需要改动其他逻辑:
// MainClass.hpp 修复后版本 #ifndef MAIN_CLASS_HPP #define MAIN_CLASS_HPP // 全局作用域前向声明FriendClass模板,不要写在MainClass内部 template <int dim> class FriendClass; template <int dim> class MainClass { public: MainClass(){}; private: // 移除内部错误的FriendClass前向声明 friend class FriendClass<dim>; double private_member = 3.0; }; #endif
额外优化建议:FriendClass.hpp的头文件保护宏存在笔误,建议从FRIEND_CLASS_CPP改为FRIEND_CLASS_HPP,避免和源文件宏定义冲突。
修复后代码可正常编译运行,FriendClass<dim>可以正确访问对应MainClass<dim>的私有成员,显式实例化逻辑不受影响,也不会产生循环依赖。
内容的提问来源于stack exchange,提问作者Lucas Myers
相关产品推荐
相关产品推荐

