9

In my example below, why do I have to fully qualify the name of the free function in the cpp to avoid linker errors and why does it work for the class function without? Can you explain the difference?

ctest.h:

namespace Test
{
    int FreeFunction();

    class CTest
    {
        public:
            CTest();
            ~CTest();
    };
}

ctest.cpp:

#include "ctest.h"

using namespace Test;

// int FreeFunction()     -> undefined reference error
int Test::FreeFunction()  -> works just fine
{
    return 0;
}

CTest::CTest()                -> no need to fully qualify name, i.e. Test::CTest
{}

CTest::~CTest()
{}

Thanks for your time & help.

nabulke
  • 11,025
  • 13
  • 65
  • 114
  • Note that specifying `void` as argument, while useful in C, is useless and considered bad style in C++: http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.4 – log0 Nov 03 '10 at 08:47
  • @Ugo: I edited my question to remove that abomination. Thanks for pointing that out. – nabulke Nov 03 '10 at 09:10

4 Answers4

12
int FreeFunction(void);  

is just a declaration whereas the below is a definition.

class CTest 
{ 
    public: 
        CTest(); 
        ~CTest(); 
}; 

If you want to provide definition for an already declared entity in a namespace (e.g. in an enclosing namespace), it has to be fully qualified name.

EDIT2:

Here is something that would give you some more clarity. Note no using directive in this code.

namespace Test { 
    int FreeFunction(void);   // declare

    class CTest;              // declare
} 

int Test::FreeFunction(){return 0;} // define
class Test::CTest{            // define
};

int main(){}

EDIT 3: Declaration vs Definition (C++0x) $3.1/2-

A declaration is a definition unless it declares a function without specifying the function’s body (8.4), it contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a function-body, it declares a static data member in a class definition (9.4), it is a class name declaration (9.1), it is an opaque-enum-declaration (7.2), or it is a typedef declaration (7.1.3), a using-declaration (7.3.3), a static_assert-declaration (Clause 7), an attribute-declaration (Clause 7), an empty-declaration (Clause 7), or a using-directive (7.3.4).

Chubsdad
  • 24,777
  • 4
  • 73
  • 129
  • Is it correct to say that in my ctest.h I define the class CTest, but I only declare the CTest member functions? – nabulke Nov 03 '10 at 07:46
  • Yes you are right. Additionally, a function can be defined inline in the namespace or be defined in any one of it's enclosing namespaces with full name qualification – Chubsdad Nov 03 '10 at 07:48
  • Very nice answer with examples and a good explanation. Helped me to understand the issue. Thanks – nabulke Nov 03 '10 at 09:56
2

While FreeFunction will resolve to Test::FreeFunction if you refer to it or call it after providing the using namespace Test; line, as far as defining the function goes, the compiler has no way to know if you're defining an entirely new function FreeFunction outside of any namespace, or whether you're defining the already declared Test::FreeFunction. The compiler defaults to thinking that you're defining an entirely new function.

For CTest::CTest, however, you're already referring to the class Test::CTest, and since there's no class or namespace CTest outside of the Test namespace, well, the reference to CTest::anything is unambiguous. So it knows that the constructor and destructor definitions refer to the in-namespace class CTest.

I think it's a small price to pay, to have to write Test::FreeFunction.

Hope this helps!

btown
  • 2,273
  • 3
  • 27
  • 38
1

If you don't qualify FreeFunction definition, the compiler does not know for sure anther you want to provide implementation for the previously forward-declared Test::FreeFunction or for a separate FreeFunction in the current namespace.

On the other hand, there's only one way to resolve the name CTest - as the class definition from the Test namespace. Thus, there's no need to fully qualify it.

However, if the CTest name resolution is ambiguous (say there's another CTest class in the current namespace as well), you will have to fully qualify the method declarations.

Franci Penov
  • 74,861
  • 18
  • 132
  • 169
0

When implementing a function it is usually preferable, I find, to open the namespace. Remember you can re-open them...

// in Test.cpp
namespace Test
{
   int FreeFunction()
   {
       return 0;
   }
}
CashCow
  • 30,981
  • 5
  • 61
  • 92