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



好吧,这真的是werid。我从来没有遇到过这样的事情。

我的程序的一部分(编译失败)包含以下三个名称空间:

// 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()'

我以前从未遇到过这样的事情。。。这看起来真的很奇怪,我甚至不知道用什么词来形容这个问题。

如果有任何帮助,我将不胜感激。

谢谢,

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

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

请参阅这个答案了解什么是声明、什么是定义以及它们的优点/需要。

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

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

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

指针编译良好,因为所有指针都相同。只是不同对象类型所允许的语义不同
在您尝试使用它之前,它会编译find。
但是要创建一个实际的对象,您需要实际的定义。

要使用来自另一个命名空间的定义,您可以使用作用域,也可以使用使用

#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!?
    }
    }

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

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

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

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

仅仅包含头是不够的,但您需要明确表示您正在使用这些头中的名称空间:

namespaceC.cc中,在包含namespace.B之后添加using namespace B;,或者更好的是,在前缀类型之前添加命名空间限定符:

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

我在Visual studio 2005中尝试了这些代码。如果我删除namespaceB.cc中构造函数和析构函数的"inline",它可以链接而不会出错。

然后我发现了这个帖子:G++赢了';t接受C++中的内联构造函数

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

最新更新