今天在友元类与命名空间结合使用时,遇到一个小问题,总结一下。
这样一个场景:
A是一个连接类,B是一个客户端类,在不同的命名空间下,在不同的头文件定义,
A希望B能够访问到自己的私有成员,所以设置B为其友元类,
B类在实例化时,需要用到A类对象进行初始化(构造函数用到A类对象指针)。
涉及到了头文件相互包含的问题,头文件中对所需的类类型进行前向声明(forward declaration),然后在.cpp文件中包含该类类型的头文件,
详细说明可参考http://www.cnblogs.com/sunrack/articles/590384.html
对不同命名空间的类型进行前向声明时,以下列方式声明,使用该类型时,需指定其所在命名空间
namespace space_name { class type_name; }
这里遇到了一个问题,
如果一个类(类型名是A)在特定命名空间(名字是nsa)下,而其友元类(类型名是B)在全局空间下,进行友元类声明时,目标类使用全局空间域操作符,
否则,A类会认为B类在nsa下,实际上B类在global空间下,所以导致编译的时候,提示B类没有权限使用A类的私有的数据或函数成员。
Linux下这个规则需要严格遵守,在Windows下使用dev-c++发现即使B类不指定全局空间,也能正常编译和运行,可能是编译器实现上不同吧。。
总结一下,涉及到不同命名空间的友元类声明,一定要指定其所在命名空间。
demo代码如下
a.h
#ifndef A_H #define A_H //forward declaration namespace nsb { class B; } namespace nsa { class A { public: A(): num_(0) {} int get_num() const { return num_; } friend class nsb::B; //friend class ::B; //if B is in global namespace, need to use "::B" private: int num_; }; } // namespace #endif
b.h
#ifndef B_H #define B_H //forward declaration namespace nsa { class A; } namespace nsb { class B { public: B(nsa::A *a); void set_num_of_A(int n); int get_num_of_A() const; private: nsa::A *pa_; }; } // namespace #endif
b.cpp
#include "b.h" #include "a.h" namespace nsb { B::B(nsa::A *pa): pa_(pa) { } void B::set_num_of_A(int n) { pa_->num_ = n; } int B::get_num_of_A() const { return pa_->num_; } } // namespace
test.cpp
#include "a.h" #include "b.h" #include <iostream> using std::cout; using std::endl; int main() { nsa::A a; nsb::B b(&a); cout << a.get_num() << endl; b.set_num_of_A(100); cout << b.get_num_of_A() << endl; return 0; }
From http://www.cnblogs.com/caosiyang/