【问题标题】:Compilation of C++ member functions defined outside the class body类体外部定义的 C++ 成员函数的编译
【发布时间】:2017-10-03 17:41:35
【问题描述】:

我有一个这样的 hpp 文件:

#ifndef __MYLIB_H
#define __MYLIB_H

class A {
public:
  void func1();
  void func2();  
};

void A::func1() {
  // maybe do something
}

#endif

有一个对应的cpp文件,里面有func2的实现。头文件包含在项目中的其他文件中(这些文件包含在更多文件中)。当我尝试构建它时,我收到func1 的“多重定义”链接器错误。为什么会发生这种情况?由于我已经用#ifndef 保护了头文件,所以我没想到会出现错误。

如果我将关键字inline 添加到func1 的定义中,那么一切都很好。因此,如果我不关心被内联的函数并且我不想在类主体中有定义,我不能在 hpp 文件中包含它的定义吗?如果有人可以解释这里发生了什么,那将非常有帮助。我正在使用 GCC 6。

【问题讨论】:

  • 这不是问题,但是包含两个连续下划线 (__MYLIB_H) 的名称和以下划线后跟一个大写字母的名称保留供实现使用。不要在你的代码中使用它们。
  • inline 并不意味着编译器会内联函数。它只允许您将它包含在多个位置(即具有多个定义)。类体内定义的函数隐式为inline
  • @PeteBecker 那么也许我可以使用 MYLIB_H 代替?
  • MYLIB_H -- 当然。

标签: c++ inline


【解决方案1】:

回想一下,整个标题的内容,连同它可能包含的任何文件,实际上被“复制粘贴”到每个翻译单元*,其中包括包含点的标题。

这就是为什么在多个 CPP 文件中包含头文件的效果与您将函数定义复制粘贴到每个 CPP 中的效果相同,即它与您为同一个成员函数编写多个相同的定义相同.

通过声明函数inline来解决问题,因为C++允许内联函数的多个定义,只要它们彼此相同。将函数体移动到类的声明中也可以,因为这些函数会自动被视为inline

* 在这种情况下,“翻译单元”是 CPP 文件的一个花哨名称。

【讨论】:

    【解决方案2】:

    问题是您在每个文件中都重新定义了func1

    #include 指令是一个非常简单的命令,它只是将头文件的内容粘贴到指定的位置。

    这样做的结果是,每次您 #include 您的标头时,您都在该文件中“重新定义”func1

    【讨论】:

      【解决方案3】:

      实现通常放在关联的.cpp 文件中。将它们放在标题中是有问题的。 inline 是一种解决此问题的技巧,您可能不想使用它,因为它会在出现的任何地方消除该代码,从而导致大量重复。

      请记住,#include 就像将该文件粘贴到该指令出现的代码中一样。对一个函数有多个实现是不正确的,这就是为什么将它们拆分为用于签名目的的标头,因此了解如何正确使用这些函数以及实际代码的实现。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-20
        • 2012-08-07
        • 2011-01-07
        相关资源
        最近更新 更多