C++友元类与命名空间的结合使用

今天在友元类与命名空间结合使用时,遇到一个小问题,总结一下。

这样一个场景:

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/
原文地址:https://www.cnblogs.com/caosiyang/p/2731274.html