Cannot create an instance of a class from another

2019-09-20 01:23发布

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,

8条回答
\"骚年 ilove
2楼-- · 2019-09-20 01:38

You have to write the constructor and destructor for B::Tree somewhere either inline or in namespaceB.cc. By creating an instance of B, you are requiring the existence of the constructor and destructor.

查看更多
SAY GOODBYE
3楼-- · 2019-09-20 01:43

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:

#include "namespace.B"
using namespace B;
namespace C {
void run() {
    Tree *tree;    // FINE
    Tree tree;     // Fail to compile!?
}
}

or:

   #include "namespace.B"
    namespace C {
    void run() {
        B::Tree *tree;    // FINE
        B::Tree tree;     // Fail to compile!?
    }
    }
查看更多
我想做一个坏孩纸
4楼-- · 2019-09-20 01:54

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 add using namespace B; after you include namespace.B or, even better, prepend types with a namespace qualifier:

B::Tree *tree;    
B::Tree tree;     
查看更多
仙女界的扛把子
5楼-- · 2019-09-20 01:55

Your definitions of B::Tree::Tree() and B::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.

查看更多
【Aperson】
6楼-- · 2019-09-20 01:57

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.

查看更多
再贱就再见
7楼-- · 2019-09-20 02:01
 namespaceC.cc: undefined reference to `B::Tree::Tree()'
 namespaceC.cc: undefined reference to `B::Tree::~Tree()'

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.

查看更多
登录 后发表回答