2011-03-04 65 views
1

我有一些在Visual Studio上运行良好的代码,现在我正试图在g ++上编译它。它在一堆地方给我'对SomeClass :: someMethod()const'的未定义引用。g ++在visual studio很高兴的时候给出错误 - 未定义的参考

最常见的,它是以下情况:

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 [email protected] 

.cpp.o: $(CC)$(CFLAGS)$ < -o $ @

最初列出的代码行在OutputControl.cpp。它正在指向一个SomeListNode并重复它。 getNext()返回指向另一个SomeListNode的指针。

也可能会注意到,这只发生在静态函数中。

+2

这看起来像你实现了你自己的链表。你确定你不想使用'std :: list'吗? – 2011-03-04 09:21:08

+1

@ Space_C0wb0y你说得对,虽然我会修改它很多,并专注于它。从我完成C++开始已经有一段时间了,所以我正在逐步回到它。 – socks 2011-03-04 09:22:32

+1

请编辑您的问题以包含涉及.cpp文件的列表以及您使用的编译/链接命令行。 – Erik 2011-03-04 09:30:07

回答

0

将所有.cpp文件传递给g ++编译命令。

g++ -g -Wall -o myapp File1.cpp File2.cpp File3.cpp 

编辑:

如果你使用静态库,你应该添加在G ++命令行这些最后

链接器进程按顺序传递文件,当它遇到静态库时,它将搜索到目前为止未定义的符号。您可以使用--whole-archive

+0

他们都被传递给它,已经 – socks 2011-03-04 09:22:54

+0

在一个g ++调用中,还是多个? – Erik 2011-03-04 09:28:04

+0

在一个单一的,通过一个生成文件 – socks 2011-03-04 09:29:38

2

您只能在const限定的对象上调用const限定的方法。如果getNext()不是const,那么你应该使用SomeListNode *node而不是const SomeListNode *node

+2

他得到一个链接器错误,未定义的引用,而不是他会得到的编译器错误,如果一个const成员函数丢失。 – Erik 2011-03-04 09:23:45

+0

Erik是对的。无论哪种方式,getNext()都是const。 – socks 2011-03-04 09:26:29

+1

@socks:你实际上是在链接'getNext'成员函数defiend的目标文件吗? – 2011-03-04 09:27:08

1

未定义的引用是链接器错误,并且这些与标题包含无关。您必须确保您已将这些函数的定义编译到某个对象文件中,并将该对象文件传递给链接器。

请注意,如果您正在编译静态库,链接器命令行中库的顺序会影响结果。尤其是,如果一个库依赖于其他库,则该依赖库应该出现在命令行之前的所有依赖库都依赖于

无论如何,将每个目标文件分别编译到.o或库中,然后使用nm来提取每个翻译单元中定义的符号列表,这些符号会告诉您该定义是否已编译或不,并且如果您正在编译静态库,将帮助您确定顺序。

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的答案。

1

我建议你在你的makefile中设置依赖关系,这样依赖于别人的对象才会按正确的顺序生成。还设置一个干净的目标,删除.o文件。在这次运行之后,让它干净,然后制作。

这是我可以用你给我们提供的信息想到的最好的建议。

0

Visual Studio和g ++之间的一个区别是它们如何处理模板。在Visual Studio中,如果你在一个模板中定义了一个函数,但你从不在任何地方使用它,VS将不会检查它或者生成任何代码。在g ++中它会检测(如果它有任何问题,它会给你错误)。