简体   繁体   中英

friend function within a namespace

When a friend function is included in the namespace, its definition needs to be prefixed with namespace to compile it, here is the sample code:

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;
}

Compiling above code give the error :

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'

However if i use

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

It compiles, Why the function needs to be prefixed with namespace TestNamespace::testFunc but not the class, Both the class TestClass and function testFunc are included in the namespace in header.

The TestClass is being used in the testFunc method. Since you have included the namespace " using namespace TestNamespace; " it works fine.

For testFunc method you are defining the implementation, you need to tell compiler that testfunc belongs to namespace TestNamespace:

you can do it either:

in .cpp

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

OR

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

When implementing cpp's for namespaces I don't do the "using namespacename;" thing. Instead, I declare the namespace just like in the .h file and embed all the namespace code in that. Like so:

namespace Namespacename {

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

}

It avoids a lot of confusion, both for you and the compiler.

So your code should look like:

#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;
   }
}

Just as a matter of policy, I try to avoid "using" in general. It is probably acceptable for "std", but for everything else I want the reader to know where stuff came from. This isn't that much of a hardship as long as you take the attitude that the namespace should be part of the object's name when you are naming things.

For example, in your above code I'd name the namespace "Test" and take the word "Test" out of all its methods and classes. That way instead of doing a using TestNamespace; and declaring a TestClass , your client will simply declare a Test::Class . This way Test is actually a piece of compiler-imposed structure to your objects, rather than just a piece of unstructured metadata that you have to chuck onto the front of your names to imply a relationship.

There is actually no way the compiler can tell if your function definition in the cpp file

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

belongs to the already declared prototype

void TestNamespace::testFunc(TestClass &myObj);

or is a new function without a forward declaration. So the only way to resolve the ambiguity is to make you resolve the namespace. Hence the error message.

When emitting an implementation, the default namespace is the global namespace whereas:

using namespace TestNamespace;

tells the compiler 'look in here if I don't prefix' somewthing I'm referencing.

To get the behaviour you were anticipating, you could wrap the contents of the .cpp file (excluding the includes) in a whole-file namespace {} declaration

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM