重复符号 --- 定义和声明之间的差异

Duplicate symbol --- Difference between definition and declaration

本文关键字:之间 声明 符号 定义      更新时间:2023-10-16

>问题

我是C++新手,我正在做一个家庭作业问题,在控制台中绘制各种分布,但我的项目无法编译。 当我将所有内容都放在同一个文件中时,一切都很好,很花哨,但我的教授希望我们将内容拆分为一个 hpp 文件、一个 cpp 文件和一个主文件。 我刚刚将所有内容都移了过来,现在由于重复符号错误,它无法编译。

定义与声明

我知道您只想在头文件中包含函数声明,因此我添加了这些声明,但在 cpp 文件中保留了函数的实际定义。 我在 cpp 文件中有一个包含语句,其中包含头文件和另一个在 main 中.cpp其中包括 cpp 文件.
我知道我的问题可能与我的包含语句有关,但我迷失了如何解决它。

分布.hpp

这个文件是我写的四个函数的类定义和声明

#include <iostream>
class DistributionPair
{
public:
DistributionPair(std::uint32_t minValue, std::uint32_t maxValue) :
minValue(minValue),
maxValue(maxValue),
count(0)
{
}
std::uint32_t minValue;
std::uint32_t maxValue;
std::uint32_t count;
};
std::vector<DistributionPair> generateUniformDistribution(std::uint32_t, std::uint32_t, std::uint32_t, std::uint8_t);
std::vector<DistributionPair> generateNormalDistribution(std::uint32_t, float, float, std::uint8_t);
std::vector<DistributionPair> generatePoissonDistribution(std::uint32_t, std::uint8_t, std::uint8_t);
void plotDistribution(std::string, const std::vector<DistributionPair>&, const std::uint8_t);

分布.cpp

此文件包含这四个函数的其余定义

#include <iostream>
#include <iomanip>
#include <random>
#include "distributions.hpp"
std::vector<DistributionPair> generateUniformDistribution(std::uint32_t howMany, std::uint32_t min, std::uint32_t max, std::uint8_t numBins)
{......

主.cpp

这是绘制分布的主要函数

#include <iostream>
#include "distributions.cpp"
int main()
{......

错误消息

以下是我在编译代码时收到的错误消息:

duplicate symbol 'generateUniformDistribution(unsigned int, unsigned int, unsigned int, unsigned char)' in:
/Users/ryanegbert/Desktop/c++/assign2/build/RandDistributions.build/Debug/RandDistributions.build/Objects-normal/x86_64/distributions.o
/Users/ryanegbert/Desktop/c++/assign2/build/RandDistributions.build/Debug/RandDistributions.build/Objects-normal/x86_64/main.o
..........
ld: 4 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

如果我使用#include "distributions.hpp",则会出现不同的编译错误:

/Users/ryanegbert/Desktop/c++/assign2/main.cpp:6:20: error: implicit instantiation of undefined template 'std::__1::vector<DistributionPair, std::__1::allocator<DistributionPair> >'
auto uniform = generateUniformDistribution(100000, 0, 79, 40);

因为我的函数是在发行版中定义的.cpp。

我在Mac上使用Xcode v11.0。

有人对我为什么会收到这个编译错误有任何帮助吗?

请注意,这是一个链接器错误,而不是编译器错误。

将可执行构建视为一个两阶段的过程。

  • 在第一阶段,编译器读取源代码并生成 .o 文件。
  • 在第二阶段,链接器读取 .o(和其他(文件并生成可执行文件。

.o文件具有二进制代码和符号引用。编译器生成两种内容:具有已定义函数的二进制代码,以及具有已声明但未定义的函数的符号引用。链接器的任务是解决所有引用,即将所有符号引用与二进制代码相关联,以构建完整的可执行文件。

在您的示例中似乎发生的情况是,您的构建脚本正在执行以下操作:

  • 将"main.cpp"+"distributions.cpp"(包含(编译为"main.o">
  • 将"distributions.cpp"编译为"distributions.o">
  • 将"main.o"+"distributions.o"链接到最终的可执行文件中

这样,链接器就有两个来自 distributions 的编译代码副本.cpp一个在 main.o 中,另一个在 distributions.o 中

。要解决它,您必须执行以下操作之一:

  • 指示链接器仅使用"main.o"来创建可执行文件

  • 替换 #include"distributions.cpp">by#include "distributions.hpp">,以便 main.o 文件仅包含符号引用,链接器将distributions.o中的符号和代码粘合到可执行文件中。

你必须在main.cpp而不是#include "distributions.cpp"#include "distributions.hpp",但你还必须包含你的函数原型在开头所依赖的所有标头,如果"distributions.hpp"

#include <vector>
#include <cstdint>