好的,所以这真的很糟糕。我从未遇到过这样的事情。
我的程序的一部分(无法编译)包含三个名称空间如下:
// 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()'
我以前从未遇到过这样的事情......这看起来很奇怪,我甚至不知道任何描述这个问题的词汇/术语。
我非常感谢任何帮助。
谢谢,
答案 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++
它表示对于内联函数,您必须在调用该函数的每个文件中都有它的定义。因此建议在头文件中放入内联定义。