命名空间函数的多重定义

6
我很难理解为什么这段代码无法编译。
我有三个文件:
main.cpp
#include "expression.h"

int main(int argc, char** argv)
{

    return 0;
}

expression.h

#ifndef _EXPRESSION_H
#define _EXPRESSION_H

namespace OP
{
  char getSymbol(const unsigned char& o)
  {
    return '-';
  }
};

#endif /* _EXPRESSION_H */

和expression.cpp文件相关

#include "expression.h"

(当然其中还有更多内容,但是即使我将除了#include之外的所有内容都注释掉,它也不起作用)
(我使用以下命令进行编译)
g++ main.cpp expression.cpp -o main.exe

这是我得到的错误信息:
C:\Users\SCHIER~1\AppData\Local\Temp\ccNPDxb6.o:expression.cpp:(.text+0x0): multiple definition of `OP::getSymbol(unsigned char const&)'
C:\Users\SCHIER~1\AppData\Local\Temp\cc6W7Cpm.o:main.cpp:(.text+0x0): first defined here
collect2.exe: error: ld returned 1 exit status

事情是这样的,它似乎解析了两次 expression.h。如果我只使用 main.cpp 或 expression.cpp 编译它,我就不会遇到错误。编译器只是忽略我的 #ifndef 并继续进行... 有什么线索吗?

对于每个文件,函数的定义都会添加到生成的目标文件中。当程序链接时,链接器看到相同函数的两个版本,并不知道该使用哪一个。解决方法:在头文件中将函数声明为“内联函数”。 - Richard Critten
1
在程序中可以有多个定义,只要每个定义出现在不同的翻译单元中,其中包括以下每个内容:类类型、枚举类型、具有外部链接的内联函数、具有外部链接的内联变量(自C++17以来)、类模板、非静态函数模板、类模板的静态数据成员、类模板的成员函数、部分模板特化、概念(自C++20以来),只要满足以下所有条件: - Chen Li
1个回答

14
问题是它似乎两次解析expression.h。
当然会这样。您在两个不同的cpp文件中都包含了它。每个包含将头文件的内容倒入翻译单元,因此您会得到相同函数的两个定义,使链接器合理地抱怨。这与包含保护无关,后者可防止意外在同一文件中两次包含。
但是您可以在标记为内联的头文件中定义函数。所以请这样做:
namespace OP
{
  inline char getSymbol(const unsigned char& o)
  {
    return '-';
  }
}

inline这里的承诺是所有这些函数都完全相同,毫不差异。因此,多个定义实际上被视为同一函数。但是要小心不要破坏这个承诺(不要使用任何可能根据它所包含的位置改变函数体的结构)。

顺便说一下,命名空间不需要以;结束,所以我有权删除它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接