【问题标题】:C++ including a ".h" file, function duplication confusionC++ 包含一个“.h”文件,函数重复混乱
【发布时间】:2011-08-27 00:13:20
【问题描述】:

我目前正在编写一个程序,但无法弄清楚为什么会出现错误(注意:我已经修复了它,我很好奇为什么会出现错误以及这对包含 .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 - 对于这篇文章的混乱程度,我深表歉意。如果有什么我可以澄清的,请告诉我。

【问题讨论】:

  • 简化帖子的一个好主意是发布小样本文件,显示Current.ccCalledByCurrent.cc 及其各自标题的内容。

标签: c++ function include header-files


【解决方案1】:

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

// a.cpp
void f() {}

// b.cpp
void f() {}

然后

g++ a.cpp b.cpp

给予:

C:\Users\neilb\Temp\ccZU9pkv.o:b.cpp:(.text+0x0): multiple definition of `f()'

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

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

【讨论】:

  • 但是为什么当 myFunction() 只包含在 CalledByCurrent.cc 中而不包含在 .h 中时,它会看到两个同名的函数?此外,为什么当我从 Current.cc 中删除重复项时,它无法使用 CalledByCurrent.cc 中的函数?
  • @The C Man 因为跨文件解析名称是链接器所做的。
  • 所以链接器只检查名称但实际上不检查可用性?因此,尽管 Current.cc 实际上不能使用该函数,但链接器可能会将其视为重复项?
  • 嗯,它可以使用它,通过添加一个声明。但是,是的,链接器只检查名称。
  • 感谢您的帮助。我非常喜欢你的回答(我给你竖起大拇指),但我必须把我的答案选择给 Asha。由于对“全局功能”的解释,他/她的反应非常理想。
【解决方案2】:

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

编辑

您可以使用extern 关键字在另一个.cpp 文件中使用该函数。看这个例子:

//Test.cpp

void myfunc()
{

}

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

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

【讨论】:

  • Neil Butterworth's answer 有一个例子。
  • 谢谢。所以我明白为什么会有重复的错误。我不明白为什么当我从 Current.cc 中删除重复项时,我无法使用 thisFunction()(尽管重新声明它会导致重复错误)。
  • @Casey P:您可以使用extern 来实现这一点。查看编辑。
  • extern 实际上并不是必需的,因为函数默认具有extern 链接。
【解决方案3】:

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

【讨论】:

  • 没错,但上述错误与多个标头包含无关。
【解决方案4】:

这是因为只要你简单地声明一个函数,它就会被认为是在extern(全局)范围内(无论你是否在头文件中声明它)。链接器对于同一个函数签名会有多个实现。

如果这些函数是真正的辅助函数,那么将它们声明为;

static void thisFunction();

另外,如果你使用和 helper 相同的函数,那么只需在一个通用的头文件中声明它,比如:

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

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

【讨论】:

    【解决方案5】:

    这里有一些想法:

    • 您没有在头文件中添加header include guard。如果它被包含两次,您可能会收到此类错误。
    • 函数的原型(位于顶部)与其签名 100% 不匹配。
    • 你把函数的body放到了头文件中。
    • 您在两个不同的源文件中有两个相同签名的函数,但它们没有标记为static

    如果你使用 gcc(你没有说你使用的是什么编译器),你可以使用-E 开关来查看预处理器的输出。这包括扩展所有#defines 并包括所有#includes。

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

    【讨论】:

    • 即使没有标头保护也会发生此错误。您可以尝试在 2 个不同的 cpp 文件中编写一个空函数并将它们一起编译。
    • 没错。我将编辑我的答案以反映这种另一种可能性
    【解决方案6】:

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-27
      • 2014-11-26
      • 2013-03-21
      • 2011-05-07
      • 1970-01-01
      • 1970-01-01
      • 2010-12-16
      相关资源
      最近更新 更多