我有一些在Visual Studio上运行良好的代码,我现在正在尝试在g ++上编译它。它在一堆地方给了我'SomeClass :: someMethod()const'的未定义引用。
最常见的是,情况如下:
for (const SomeListNode *node = owner->some_list; node != 0; node = node->getNext())
在这种情况下,我得到'对SomeListNode :: getNext()const'的未定义引用。明确包含此类的头文件。为什么这在g ++中不合法?
修改详情
我正在使用makefile构建:
CC=g++
CFLAGS=-c -Wall -DDEBUG -g
LDFLAGS=
SOURCES=main.cpp SomeList.cpp SomeListNode.cpp Location.cpp OutputControl.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=theprogram
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $@
.cpp.o: $(CC)$(CFLAGS)$< -o $ @
最初列出的代码行位于OutputControl.cpp
。它正在指向SomeListNode
并迭代它。 getNext
()返回指向另一个SomeListNode
的指针。
也可能需要注意的是,这只发生在静态函数中。
答案 0 :(得分:2)
您只能在const限定对象上调用const限定方法。如果getNext()不是const,那么您应该使用SomeListNode *node
而不是const SomeListNode *node
。
答案 1 :(得分:1)
未定义的引用是链接器错误,它们与头部包含无关。您必须确保已将这些函数的定义编译到某个目标文件中,并将目标文件传递给链接器。
请注意,如果要编译静态库,则链接器命令行中库的顺序会影响结果。特别是,如果库依赖于其他库,则依赖项应出现在命令行之前所有依赖于库。
无论如何,将每个目标文件分别编译成.o或库并使用nm来提取每个翻译单元中定义的符号列表,这些符号应该告诉您定义是否已编译如果您正在编译静态库,将帮助您确定顺序。
答案 2 :(得分:1)
我建议您在makefile中设置依赖项,以便依赖于其他对象的对象以正确的顺序生成。还要设置一个删除.o文件的干净目标。在这个运行之后,使干净,并使。
这是我能用你给我们的信息来思考的最佳建议。
答案 3 :(得分:0)
将所有.cpp文件传递给g ++编译命令。
g++ -g -Wall -o myapp File1.cpp File2.cpp File3.cpp
编辑:
如果您正在使用静态库,则应在g ++命令行上添加 last 。
链接器按顺序处理传递的文件,当遇到静态库时,它会搜索到目前为止未定义的符号。您可以使用--whole-archive
答案 4 :(得分:0)
我建议使用nm
工具找出您遇到的符号。它可能看起来像这样:
// foo.h
class Foo{
public:
void bar();
};
// foo.cpp
#include "foo.h"
void Foo::bar()
{
}
// bar.cpp
#include "foo.h"
void baz()
{
Foo f;
f.bar();
}
> nm foo.o
00000000 T _ZN3Foo3barEv
> nm bar.o
00000000 T _Z3bazv
U _ZN3Foo3barEv
U __gxx_personality_v0
在这里你可以看到,bar.o使用了未定义的_ZN3Foo3barEv
符号(和__gxx_personality_v0
,但这是一个编译器细节),标记为U
。此符号在foo.o
中定义,我们将其标记为T
。要从受损名称中获取c ++名称,可以使用c++filt
。
> c++filt _ZN3Foo3barEv
Foo::bar()
> c++filt _Z3bazv
baz()
要调试您的问题,请检查SomeList.o和OutputControl.o文件并查找SomeListNode :: getNext实例。可能有很多输出,因此您可能希望使用nm file.o | grep 'SomeListNode.*getNext'
过滤输出。每个U
标记SomeListNode::getNext
符号形式的OutputControl.o文件必须在SomeList.o文件中具有完全匹配。
修改:已发布的Makefile的调整后答案。
答案 5 :(得分:0)
Visual Studio和g ++之间的一个区别是它们如何处理模板。在Visual Studio中,如果您在模板中定义一个函数,但从未在任何地方使用它,VS将不会对其进行类型检查或生成任何代码。在g ++中它会进行类型检查(如果有任何问题,它会给你错误。)