您的位置:首页 > 编程语言 > C语言/C++

C++ friend class与namespace冲突引起的思考

2012-09-21 03:03 330 查看
在C++中,friend class作为一种特殊的机制可以达到访问外部类私有成员的目的,因为这在某种程度上破坏了面向对象的封装性,所以friend class的应用场景非常有限。在组里的代码中,由于测试类(we call it TestSuite.cpp)需要访问被测试类的私有方法或者私有成员,而by default私有成员和函数对外是不可见的,那使用friend class也就是顺利成章的事情。

以下为一个具体实例:

class Manager

{

public:

Manager* getInstance();

friend class ManagerTesterSuite; //declaration of friend class

private:

bool execute();

};

class ManagerTesterSuite

{

public:

void runTest() {

Manager* manager = Manager::getInstance();

Assert(manager.execute());

}

}

以上例子就是一个简单的说明。不过程序的世界总是会有各种复杂的情况,今天为一个类写了测试类却总是通不过编译,错误是测试类无法访问对象类的私有成员,经过一番思考,我认为问题出在friend class的声明方式上,就是说test class并没有被正确的证明为对象类的friend class,因此它没有权限来访问对象类的私有方法。经过仔细对照,问题出在两个class存在于不同的namespace,如下:

//Manager.h

namespace A {
class Manager

{

public:

Manager* getInstance();

friend class ManagerTestSuite;

private:

bool execute();

};

}

//ManagerTestSuite.h

class ManagerTestSuite

{

private:

void runTest() {

Manager* manager = Manager::getInstance();

Assert(manager->execute()); //failed to pass compiler here

}

};

在网上搜索的相关文章之后,结论是在Manager中声明ManagerTestSuite是不可见的,因为Manager属于namespace A, 但ManagerTestSuite属于global namespace,解析错误。解决方法有两个: 1.把ManagerTestSuite也放到同一个namespace中,变成 namespace A { class ManagerTestSuite {...}; }; 方法二是在Manager class中正确声明ManagerTestSuite,包括前置声明ManagerTestSuite,毕竟在声明friend class的时候明确说明global namespace,这个代码应该如下:

//Manager.h

class ManagerTestSuite; //前置声明

namespace A

{

class Manager

{

public:

Manager* getInstance();

friend class ::ManagerTestSuite; //显示声明为全局namespace

private:

bool execute();

};

}

问题貌似解决了,但是我的疑问是,为什么子命名空间(namespace A)的class无法直接声明父命名空间(global namespace)中的class?认真搜索了下namespace的机制和friend class的用法。原来问题的关键在于在命名空间A中的class声明friend class的时候,相当于在namespace A中加入了一条friend class的前置声明,但是friend class不存在于空间A中,所以前置声明无效,从而friend class的声明也就失效了。换句话说,friend class在子命名空间是可见的,但是做前置声明的时候还是需要将完整的namespace路径搞对,在这个例子中,需要显示的表明friend class存在于global namespace中。因此,解决办法就是显示的在namespace A外面前置声明friend class,并且在声明friend class的时候显示标明是"::"全局空间下的class,这样就全部打通了,friendship也就建立起来了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: