无法从另一个命名空间创建类的实例?

时间:2012-02-23 14:07:04

标签: c++ class namespaces

好的,所以这真的很糟糕。我从未遇到过这样的事情。

我的程序的一部分(无法编译)包含三个名称空间如下:

// 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

现在,g ++很好,但链接器ld抱怨:

 "namespaceC.cc: undefined reference to `B::Tree::Tree()'
 "namespaceC.cc: undefined reference to `B::Tree::~Tree()'

我以前从未遇到过这样的事情......这看起来很奇怪,我甚至不知道任何描述这个问题的词汇/术语。

我非常感谢任何帮助。

谢谢,

8 个答案:

答案 0 :(得分:3)

 namespaceC.cc: undefined reference to `B::Tree::Tree()'
 namespaceC.cc: undefined reference to `B::Tree::~Tree()'

不是编译器错误 ,它们是 链接器错误 。问题是您 声明了 构造函数和析构函数,但从未 定义 。因此编译器找到声明并接受它们,但 链接器找不到定义 来链接引用。

请参阅 this answer 了解什么是声明,什么是定义以及它们的优点/需要。

答案 1 :(得分:2)

您对B::Tree::Tree()B::Tree::~Tree()的定义是内联声明的。这意味着它们仅在该源文件中可用,而不是任何其他文件。

从定义中删除inline,或将内联定义移动到需要它们的所有源文件包含的头文件中,应该修复链接错误。

答案 2 :(得分:1)

您必须在内联或 namespaceB.cc 的某处编写B::Tree的构造函数和析构函数。通过创建B的实例,您需要存在构造函数和析构函数。

答案 3 :(得分:0)

指针编译很好,因为所有指针都是相同的。它只是允许不同对象类型的语义不同 它会编译查找,直到你试图使用它为止 但是要创建一个实际的对象,您需要实际的定义。

要使用其他命名空间中的定义,您可以使用范围,也可以使用 using

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

或:

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

答案 4 :(得分:0)

您声明了Tree构造函数&析构函数,但是你没有告诉我们你在哪里定义它们(你只是说你在namespaceB.cc中实现了树)

假设您已定义它们,您必须确保在链接行中包含namespaceC.o namespaceB.o。

答案 5 :(得分:0)

这不是名称空间问题,也不是编译器错误。编译器很高兴,但链接器无法找到B::Tree::Tree()的定义。您需要提供源文件以供实现,或使用-c标志来“只编译”。

答案 6 :(得分:0)

首先,您自己声明了类Tree的构造函数和析构函数,因此编译器没有提供默认实现 - 您需要自己实现它们! (或者只是删除那些声明......)。

仅包含标题是不够的,但您需要明确说明您正在使用这些标题中的命名空间:

namespaceC.cc之后添加using namespace B;之后添加namespace.B,或者更好的是,使用命名空间限定符预先添加类型:

B::Tree *tree;    
B::Tree tree;     

答案 7 :(得分:0)

我尝试了Visual Studio 2005中的代码。如果我在namespaceB.cc中删除构造函数和析构函数中的“inline”,它可以无错误地链接。

然后我发现了这篇文章:G++ won't accept inline constructors in C++

它表示对于内联函数,您必须在调用该函数的每个文件中都有它的定义。因此建议在头文件中放入内联定义。