tags:

views:

328

answers:

4

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.

A: 

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

Ruben Bartelink
+7  A: 

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;
}
aJ
declaring testFun() in header within namespace TestNamespace is not enough for compiler to include function definition in the namespace?
Suresh
Compiler cannot distinguish whether you are writing the definition for TestNamespace testfunc or any other global testfunc
aJ
+5  A: 

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.

T.E.D.
I would even avoid a "using namespace std" since it would heavily pollute the global namespace because std has so much stuff in it's namespace.
rstevens
@rsteven: I avoid that one as well. I'm just a bit more understanding with those who don't see that one my way.
T.E.D.
+3  A: 

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.

Frank Bollack
Not exactly, that definition specifically refers to testFunc in the global namespace (a `using` statement has no effect on this). The error message is caused by the fact that this function is trying to access private data but is not the one that was declared friend.
Sumudu Fernando