命名空间中的友元函数

时间:2009-11-17 14:36:58

标签: c++ namespaces

当一个友元函数包含在命名空间中时,它的定义需要以命名空间为前缀来编译它,这里是示例代码:

test.h:

#ifndef TEST_H
#define TEST_H
namespace TestNamespace
{
    class TestClass
    {
    public:
        void setValue(int &aI);
        int value();
    private:
        int i;
        friend void testFunc(TestClass &myObj);
    };
void testFunc(TestClass &myObj);
}
#endif

TEST.CPP:

#include "test.h"

using namespace TestNamespace;

void TestClass::setValue(int &aI)
{
    i=aI;
}

int TestClass::value()
{
    return i;
}

void testFunc(TestClass &myObj)
{
    int j = myObj.i;
}

编译上面的代码会出错:

1>c:\qtprojects\namesp\test.cpp(17) : error C2248: 'TestNamespace::TestClass::i' : cannot access private member declared in class 'TestNamespace::TestClass'
1>        c:\qtprojects\namesp\test.h(11) : see declaration of 'TestNamespace::TestClass::i'
1>        c:\qtprojects\namesp\test.h(6) : see declaration of 'TestNamespace::TestClass'

但是,如果我使用

void TestNamespace::testFunc(TestClass &myObj)
{
    int j = myObj.i;
}

它编译,为什么函数需要以命名空间TestNamespace :: testFunc为前缀而不是类,类TestClass和函数testFunc都包含在头文件中的命名空间中。

4 个答案:

答案 0 :(得分:9)

TestClass方法正在使用testFunc。由于您已包含名称空间“using namespace TestNamespace;”,因此可以正常使用。

对于您定义实现的testFunc方法,您需要告诉编译器testfunc属于命名空间TestNamespace:

你也可以这样做:

in .cpp

namespace TestNamespace
{
    void testFunc(TestClass &myObj)
     {
        int j = myObj.i;
     }
 }

OR

void TestNamespace::testFunc(TestClass &myObj)
{
    int j = myObj.i;
}

答案 1 :(得分:5)

在为命名空间实现cpp时,我没有执行“using namespacename;”事情。相反,我声明命名空间就像在.h文件中一样,并在其中嵌入所有命名空间代码。像这样:

namespace Namespacename {

  classname::methodname () { ... };
  ...etc.

}

它为您和编译器避免了很多混淆。

所以你的代码应该是这样的:

#include "test.h"
namespace TestNamespace {
   void TestClass::setValue(int &aI)
   {
       i=aI;
   }
   int TestClass::value()
   {
       return i;
   }
   void testFunc(TestClass &myObj)
   {
       int j = myObj.i;
   }
}

就政策问题而言,我总体上试图避免“使用”。 “std”可能是可以接受的,但对于其他一切我希望读者知道来自哪里。只要您在命名事物时采取命名空间应该成为对象名称的一部分的态度,这就不是那么困难了。

例如,在上面的代码中,我将命名空间命名为“Test”,并从其所有方法和类中取出“Test”一词。这样,您的客户端只需声明using TestNamespace;,而不是执行TestClass并声明Test::Class。这样,Test实际上是一个编译器强加给你的对象的结构,而不仅仅是一段非结构化的元数据,你必须把它们放在你名字的前面以暗示一段关系。

答案 2 :(得分:4)

实际上,编译器无法判断cpp文件中的函数定义是否

void testFunc(TestClass &myObj)
{
    int j = myObj.i;
}

属于已经声明的原型

void TestNamespace::testFunc(TestClass &myObj);

或者是没有前瞻声明的新功能。因此,解决歧义的唯一方法是使解析命名空间。因此错误信息。

答案 3 :(得分:0)

在发布实现时,默认命名空间是全局命名空间,而:

using namespace TestNamespace;

告诉编译器'如果我没有为我引用的某些内容添加前缀,请查看此处。

要获得您预期的行为,您可以将.cpp文件的内容(不包括include)包装在整个文件命名空间{}声明中