我几天来遇到这个奇怪的链接问题。
我有一个带有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文件,然后在库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
这是我得到错误的地方:
未定义对“ namespace2 :: B”的引用
未定义引用'namespace2 :: B :: functionB()const'
我已经检查了是否所有虚函数都在B中被覆盖,这似乎还可以。同样,当我在namespace2中的其他代码中使用类B时,也没有问题,一切都可以编译。调用B.h中定义的函数是可行的,因此看起来链接程序无法访问B.cpp中定义的函数?
有什么建议么?
最佳答案
使用名称空间时,应将类方法的实现包装到.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()
分别位于全局名称空间中,而不是在名称空间1和名称空间2中。子句
using namespace_name;
并未在cpp文件中定义范围。它只是通知编译器调查该名称空间,以解决它将在该转换单元中找到的符号。您尝试填充向量时遇到的错误可能是由于您的类型缺少
functionB()
的实现,因为它位于错误的(全局)名称空间中。因此,类型B是不完整的,不能用于实例化模板类。编辑:
作为下面评论的后续内容,经过一番尝试和错误后,结果发现在代码方面,一切都很好,但是由于lib A和B之间的循环依赖关系,链接失败,在此虚拟示例中看不到该依赖关系,并且由于其他依赖关系需要正确的链接顺序才能正常工作。
因此,对库的链接顺序进行简单更改是不可行的。我的建议是,如果可能的话,避免循环依赖,或者使用ld特定的选项--start-group和--end-group解决此类问题。在与ld相关的gnu man pages中了解更多信息。您可以通过Internet在其用法上找到很多示例。
希望这可以帮助您解决问题。