为什么我会收到“多重定义”错误?我如何解决它?

los*_*ost 5 c++ g++ linker-errors

终端给出的命令:

g++ main.cpp 测试.cpp

错误信息:

/tmp/ccvgRjlI.o: 在函数 `test2()' 中:
test.cpp:(.text+0x0): `test2()' 的多重定义
/tmp/ccGvwiUE.o:main.cpp:(.text+0x0 ): 首先在这里定义
collect2: error: ld returned 1 exit status main.cpp

源代码:

#include "test.hpp"
int main(int argc, char *argv[])
{
    test2();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

测试.hpp

#ifndef _TEST_HPP_
#define _TEST_HPP_

#include <iostream>

void test();
void test2() { std::cerr << "test2" << std::endl; }

#endif
Run Code Online (Sandbox Code Playgroud)

测试.cpp

#include "test.hpp"

using std::cerr;
using std::endl;

void test() { cerr << "test" << endl; }
Run Code Online (Sandbox Code Playgroud)

顺便说一句,以下编译良好:

g++ main.cpp

Vla*_*cow 4

标头test.hpp包含在两个编译单元中。第一个是编译单元main.cpp,第二个是编译单元test.cpp

默认情况下,函数具有外部链接。这意味着具有相同名称和签名的函数在不同编译单元中表示相同的函数。它们应被定义一次。但是,在您的程序中,该函数的定义test2是在两个编译单元中找到的,并且链接器不知道要使用该函数的哪个定义。

您可以将该函数声明为内联函数。例如

inline void test2() { std::cerr << "test2" << std::endl; }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它可以在每个编译单元中定义。

或者,您可以仅将您使用函数所做的函数声明放置在标头中test,并在例如test.cpp.

另一种方法是将函数声明为具有内部链接。为此,您可以使用关键字 static 在标头中定义该函数

static void test2() { std::cerr << "test2" << std::endl; }
Run Code Online (Sandbox Code Playgroud)

或将其放置在未命名的名称空间中

namespace
{
    void test2() { std::cerr << "test2" << std::endl; }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,每个编译单元都有自己的功能test2