提问人:hewy 提问时间:8/9/2014 更新时间:8/9/2014 访问量:4859
对头文件外部定义的成员函数的 C++ 未定义引用
c++ undefined reference to member function defined outside of header file
问:
在我的印象中,您可以在一个文件中定义一个类的成员函数,然后在另一个文件中使用这些函数,只要两个文件都经过编译并发送到链接器即可。但是,如果我使用 g++ (4.6.4),这样做会给我一个未定义的引用错误。有趣的是,使用英特尔编译器 (icpc 11.0) 不会出现错误,一切正常。我是否可以在 g++ 中设置一些标志来使其工作,或者英特尔编译器是否让我逃脱了我不应该做的事情?以下是重现我问题的一些代码:
class.h:
#ifndef _H
#define _H
typedef class
{
public:
int a;
int b;
void set(int x, int y);
int add(void);
} Test;
#endif
类.cpp:
#include "class.h"
void Test::set(int x, int y)
{
a = x;
b = y;
}
int Test::add(void)
{
return a+b;
}
main.cpp:
#include <cstdio>
#include "class.h"
int main(void)
{
Test n;
n.set(3, 4);
printf("%d\n", n.add());
return 0;
}
为了编译,我做:
$ g++ class.cpp main.cpp -o test
/tmp/ccRxOI40.o: In function `main':
main.cpp:(.text+0x1a): undefined reference to `Test::set(int, int)'
main.cpp:(.text+0x26): undefined reference to `Test::add()'
collect2: ld returned 1 exit status
答:
5赞
jxh
8/9/2014
#1
好吧,这很奇怪,但发生的事情是这个结构:
typedef class
{
public:
int a;
int b;
void set(int x, int y);
int add(void);
} Test;
虽然编译器在语义上没有将 legal 视为:
class Test
{
public:
int a;
int b;
void set(int x, int y);
int add(void);
};
该版本将方法用于文件,如输出中所示:typedef
static
nm
$ nm class.o
0000000000000024 t _ZN4Test3addEv
0000000000000000 t _ZN4Test3setEii
U __gxx_personality_v0
虽然版本使它们成为正确的方法:class Test
$ nm class2.o
0000000000000024 T _ZN4Test3addEv
0000000000000000 T _ZN4Test3setEii
U __gxx_personality_v0
这就是链接器找不到符号的原因。
编辑:至于为什么会发生这种情况,似乎是由于解释标准如何指定将名称视为类名的问题。较新的编译器似乎没有表现出同样的问题。此问题中报告的问题在 g++ 4.4.7 中重现。
typedef
如果您将文件中的代码移动到并且仅编译,则事情将起作用。或者,可以将方法定义内联到 中。class.cpp
main.cpp
main.cpp
class.h
如果要将它们保留为单独的翻译单元,则需要更改文件,以便使用 way 而不是使用 on 匿名类来定义类。class.h
class Test
typedef
评论
0赞
hewy
8/9/2014
谢谢,这奏效了,你知道为什么会这样吗?我以为这两个版本是等价的。
0赞
jxh
8/9/2014
因为你声明了一个匿名类。由于该类实际上没有名称,因此 C++ 编译器认为尝试解析与该类的方法相关的全局符号是违规的。因此,它使您的方法文件成为本地文件。这是一个相关的问题。.
1赞
Ben Voigt
8/9/2014
引入的名称是类名*,而标准要求在类外部定义的每个成员函数都使用“其类名”(单数)。不是“其类名之一”(复数),其中包括由 创建的类名。似乎该标准可以对此进行一些澄清。typedef
typedef
0赞
jxh
8/9/2014
@BenVoigt:谢谢,所以我应该把“不洁食”的措辞改成表明正确的处理方式是模棱两可的?
1赞
aschepler
8/9/2014
但是 7.1.3/9 呢?“如果 typedef 声明定义了一个未命名的类(或枚举),则声明声明为该类类型(或枚举类型)的第一个 typedef-name 用于表示类类型(或枚举类型),仅用于链接目的 (3.5)。”3.5 特别指出,此类类及其成员具有外部联系。
评论
typedef
class Test {};
_H
保留用于实现,选择合法标识符。-std=c++11
-std=c++0x
g++ class.cpp main.cpp
g++ -c class.cpp -o class.o
g++ -c main.cpp -o main.o
g++ class.o main.o -o test
-Wall -Wextra -pedantic
-std=...
gnu++98