我现在有这个奇怪的连接问题了几天。 我有一个带有2个命名空间的C ++项目(在Ubuntu 16.04中)。每个命名空间都有一个单独的目录中的.h和.cpp文件,这些目录编译成库.a文件。最后,所有内容都链接到一个可执行文件中。
该项目非常庞大(OpenBTS的修改)所以为了使它更容易,这基本上是我想要做的:
//*****directory A:
//file: A.h
namespace1 {
class A {
public:
void functionA();
};
}
//file: A.cpp
#include <B.h>
#include <vector.h>
using namespace1;
using namespace2;
void A::functionA (){
B testB1;
B testB2;
testB2 = testB1; //works
testB1.functionB2(); //defined in B.h, works
testB1.functionB(); //undefined reference to 'namespace2::B::functionB() const'
std::vector<B> testvector;
testvector.push_back(testB1); //undefined reference to 'namespace2::B'
}
//
//******directory B:
//file: B.h
#include "C.h"
//class C was part of the project before I started editing it and should not be the problem because other classes derived from it compile without problem.
namespace 2{
class B: public C{
int varB;
public:
B(){};
~B(){};
void functionB() const; //overrides virtual functionB in class C
int functionB2() { return varB;}
void functionB2() //overrides pure virtual functionB2 in class C
};
}
//file B.cpp
#include "B.h"
using namespace2
void B::functionB(){
//code...
}
//main.cpp
//this creates an instance of A
最后,目录A中的所有文件都在.o文件中编译,然后在libary A.a中链接在一起,对于目录B也是如此。另外main.cpp编译为main.o
然后所有人都联系在一起: g ++ -g -O2 -Wall -pthread -rdynamic -o exename main.o ../B/.libs/B.a ../A/.libs/A.a -la53 -lzmq -pthread
这是我收到错误的地方:
未命名引用&#39; namespace2 :: B&#39; 未定义引用&#39; namespace2 :: B :: functionB()const&#39;
我已经检查过B中是否覆盖了所有虚拟功能,这似乎没问题。此外,当我在namespace2中的其他代码中使用B类时,没有问题,所有内容编译都很好。调用B.h中定义的函数是有效的,因此链接器似乎无法访问B.cpp中定义的函数吗?
有什么建议吗?
答案 0 :(得分:2)
使用命名空间时,您应该将类的方法实现包装到.cpp文件中的命名空间中。你的a.cpp应该类似于:
//file: A.cpp
#include <B.h>
#include <vector.h>
namespace namespace1 {
using namespace2; // means 'look in namespace2' to the compiler
void A::functionA (){
B testB1;
B testB2;
testB2 = testB1;
testB1.functionB2();
testB1.functionB();
std::vector<B> testvector;
testvector.push_back(testB1);
}
} // namespace1
你的b.cpp应该是这样的:
//file B.cpp
#include "B.h"
namespace namespace2 {
void B::functionB() const{
//code...
}
} // namespace2
请注意,类型B对象的实例化是有效的,因为构造函数是在类声明中定义的。同样适用于B::function2()
。另一方面,A::functionA()
和B::functionB()
在全局命名空间中,而不是在namespace1和namespace2中,因为它们应该如此。
子句using namespace_name;
未定义cpp文件中的范围。它只是通知编译器查看该命名空间以解析它将在该转换单元中找到的符号。
尝试填充向量时得到的错误可能是由于您的类型缺少functionB()
的实现,因为它位于错误的(全局)命名空间中。因此,类型B不完整,不能用于实例化模板类。
编辑: 作为下面的评论的后续,经过一些试验和错误后,事实证明在代码方面一切都很好,但由于lib A和B之间的循环依赖关系导致链接失败,这在这个虚拟示例中并不清晰可见,以及因为需要正确的链接顺序才能工作的其他依赖项。
因此,库的链接顺序的简单改变是不可行的。我的建议是尽可能避免循环依赖,或者使用ld特定选项 - start-group 和 - end-group 来解决此类问题。在与ld相关的gnu man pages了解详情。你会在互联网上找到很多关于它们用法的例子。
希望这有助于解决您的问题。
答案 1 :(得分:0)
我认为它与这个名为text的函数有关(std :: ostream&amp;)
在B.h中有:
class B {
...
void text(std::ostream&) const;
}
在B.cpp中有(包含在namespace2中):
void B::text(std::ostream& os) const {
os << "some text";
}
如果我删除B.cpp中的定义并在B.h中声明和定义:
class B {
...
void text(std::ostream&) const {}; //no link problems!
}
直接在.h中定义,它将成功编译。
请注意,text()会覆盖C类中的虚函数,在C.h中声明为:
virtual void text(std::ostream& os) const
{ os << "(no text())"; }
我还试图在B.h中的函数之前添加虚拟,但这并没有解决问题。