Okay, so this is really werid. I've never encountered anything like this.
Part of my program (Fails to compile) contains three namespaces as following:
// namespaceA.h
namespace A {
enum Kind { jimmy, david };
}
// end of namespaceA.h
// namespaceB.h
#include "namespaceA.h"
namespace B {
class Tree {
public:
Tree *prev;
Tree *next;
Tree *down;
A::Kind kind;
Tree();
~Tree();
};
}
// end of namespaceB.h
// Implementation details of the class are placed in namespaceB.cc
// Constructor / Desctructor defined in the namespaceB.cc file!
// Something like this,
#include "namespaceB.h"
namespace B {
inline Tree::Tree() { ... }
inline Tree::~Tree() { ... }
}
// namespaceC.cc
#include "namespace.B"
namespace C {
void run() {
B::Tree *tree; // FINE
B::Tree tree; // Fail to compile!?
}
}
// end of namespaceC.cc
Now, g++ went along just fine but the linker ld complains:
"namespaceC.cc: undefined reference to `B::Tree::Tree()'
"namespaceC.cc: undefined reference to `B::Tree::~Tree()'
I have never ever encountered anything like this before... This just seems really weird, I don't even know any words/terms to describe this problem.
I would much appreciate any help.
Thanks,
You have to write the constructor and destructor for
B::Tree
somewhere either inline or in namespaceB.cc. By creating an instance ofB
, you are requiring the existence of the constructor and destructor.The pointer compiles fine because all pointers are the same. It's just the semantics allowed for different object types differ.
It would have compiled find up until the point you tried to use it.
But to create an actual object, you need the actual definition.
To use definitions from another namespace, you either used scopes, or use using:
or:
First, you declared constructor and destructor of class
Tree
yourself so compiler didn't provide default implementation - you need to implement them yourself! (Or just remove those declarations...).It is not enough to include headers but you need to explicitly say that you're using namespaces from those headers:
In
namespaceC.cc
addusing namespace B;
after you includenamespace.B
or, even better, prepend types with a namespace qualifier:Your definitions of
B::Tree::Tree()
andB::Tree::~Tree()
are declared inline. This means they are only available in that source file, not any others.Either removing
inline
from the definitions, or moving the inline definitions into a header file included by all source files that need them, should fix the link errors.I tried the codes in Visual studio 2005. If I remove the "inline" in namespaceB.cc for the constructor and destructor, it can link without errors.
Then I found this post: G++ won't accept inline constructors in C++
it says that for inline functions you must have its definition in every file that calls the function. So it is recommended to put inline definition in header file.
Those are not compiler errors, they are linker errors. The problem is that you declared the constructor and destructor, but never defined them. So the compiler finds the declarations and accepts them, but the linker cannot find the definitions to link the references to.
See this answer for what is a declaration and what is a definition and what they are good/needed for.