C++包括".h"文件,功能重复混淆

C++ including a ".h" file, function duplication confusion

本文关键字:功能 包括 文件 C++      更新时间:2023-10-16

我目前正在编写一个程序,无法弄清楚为什么会出现错误(注意:我已经修复了它,我很好奇为什么会出现错误以及这意味着什么包括.h文件)。

基本上,我的程序结构如下:

我正在使用的当前文件,我将调用Current.cc(这是Current.h的实现)。

Current.cc包含一个名为 CalledByCurrent.h 的头文件(该文件具有一个名为 CalledByCurrent.cc 的关联实现)。 CalledByCurrent.h包含一个类定义。

CalledByCurrent.cc中定义了一个名为 thisFunction() 的非类函数。 thisFunction()没有在CalledByCurrent.h中声明,因为它实际上不是类的成员函数(只是一个小的帮助函数)。 在Current.cc中,我需要使用这个函数,所以我只是在Current.cc的顶部重新定义了thisFunction()。 但是,当我这样做时,我收到一个错误,说该功能重复。 为什么会这样,当myFunction()甚至没有在CalledByCurrent.h中宣布时?

因此,我只是从Current.cc中删除了该函数,现在假设Current.cc可以从CalledByCurrent.cc访问thisFunction()。 但是,当我这样做时,我发现Current.cc不知道我在说什么功能。 什么鬼? 然后,我将thisFunction()的函数定义复制到CalledByCurrent.h文件的顶部,这解决了问题。 你能帮我理解这种行为吗? 特别是,为什么它会认为有副本,但它不知道如何使用原件?

p.s - 对于这篇文章的混乱程度,我深表歉意。 如果有什么我可以澄清的,请告诉我。

您正在从链接器获得多个定义 - 它看到两个同名的函数并抱怨。例如:

// a.cpp
void f() {}
// b.cpp
void f() {}

然后

g++ a.cpp b.cpp

给:

C:UsersneilbTempccZU9pkv.o:b.cpp:(.text+0x0): multiple definition of `f()'

解决方法是将定义仅放在一个.cpp文件中,或者将一个或两个函数声明为静态:

// b.cpp
static void f() {}

不能有两个同名的全局函数(即使在 2 个不同的翻译单元中也是如此)。为避免出现链接器错误,请将函数定义为static,使其在翻译单元外不可见。

编辑

您可以使用extern关键字在其他.cpp文件中使用该函数。请参阅此示例:

//Test.cpp
void myfunc()
{
}
//Main.cpp
extern void myfunc();
int main()
{
    myfunc();
}

它将调用test.cpp中定义的myfunc()

头文件包含机制应容忍重复的头文件包含。

这是因为每当你简单地声明一个函数时,它都会被考虑在extern(全局)范围内(无论你是否在头文件中声明它)。链接器将具有同一函数签名的多个实现。

如果这些函数确实是帮助程序函数,则将它们声明为;

static void thisFunction();

另一种方式,如果您使用与 helper 相同的函数,那么只需在公共头文件中声明它,例如:

//CalledByCurrent.h  (is included in both .cc files)
void thisFunction();

并在任一 .cc 文件中实现 thisFunction()。这应该可以正确解决问题。

这里有一些想法:

  • 您没有在头文件中放置标头包含保护。 如果它被包含两次,您可能会收到此类错误。
  • 函数的原型(顶部)与其签名 100% 不匹配。
  • 将函数的主体放在头文件中。
  • 您在两个不同的源文件中有两个具有相同签名的函数,但它们未标记为static

如果您使用的是 gcc(您没有说明您正在使用的编译器),则可以使用 -E 开关查看预处理器输出。 这包括扩展所有#define并包括所有#include

每次展开某些内容时,它都会告诉您它在哪个文件和行中。 使用它,您可以看到定义thisFunction()的位置。

2 个不同的错误来自构建的 2 个不同阶段。

在第一种情况下,您有一个重复项,编译器很高兴,但 LINKER 抱怨,因为当它拾取不同源文件中的所有函数定义时,它注意到 2 个被命名为相同。如其他答案所述,您可以使用 static 关键字或使用通用定义。

在第二种情况下,您看到您的函数未在此范围内声明,这是因为 COMPILER 抱怨,因为每个文件都需要知道它可以使用哪些函数。

编译发生在链接之前,因此编译器无法提前知道链接器是否会找到匹配的函数,这就是为什么您使用声明来通知编译器稍后链接器将找到定义。

如您所见,您的 2 个错误并不矛盾,它们是构建中具有特定顺序的 2 个独立进程的结果。