如何为函数正确创建 header 而不会出现多重定义错误?

How to properly create a header for functions, without multiple definitions error?

我有一个header,它定义了我需要的一些功能。我将它们包含在两个文件中,它们本身包含在 main.cpp 中,但我得到了函数错误的多个定义,尽管我把

#ifndef MYFUNCTION_H
#define MYFUNCTION_H
//code
#endif

在我的代码中。 那我做错了什么?这是我的 header:

#ifndef EXTRASFMLFUNCTIONS_H
#define EXTRASFMLFUNCTIONS_H

#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Text.hpp>

inline void setCenterPos(sf::Sprite &entity, const sf::Vector2f& position)
{
    entity.setPosition(sf::Vector2f{(position.x - entity.getGlobalBounds().width / 2), position.y - (entity.getGlobalBounds().height / 2)});
}

inline void setCenterPos(sf::Text &entity, const sf::Vector2f& position)
{
    entity.setPosition(sf::Vector2f{(position.x - entity.getGlobalBounds().width / 2), position.y - (entity.getGlobalBounds().height / 2)});
}

inline sf::Vector2f getCenter(const sf::Sprite& entity)
{
    return sf::Vector2f{entity.getGlobalBounds().width / 2, entity.getGlobalBounds().height / 2} + entity.getPosition();
}

inline void scaleTo(sf::Sprite& entity, const sf::Vector2f& size)
{
    entity.scale(size.x / entity.getGlobalBounds().width, size.y / entity.getGlobalBounds().height);
    return;
}

inline void scaleToWidth(sf::Sprite& entity, const float &width)
{
    entity.scale(width / entity.getGlobalBounds().width, width / entity.getGlobalBounds().width);
    return;
}

inline void scaleToHeight(sf::Sprite& entity, const float &height)
{
    entity.scale(height / entity.getGlobalBounds().height, height / entity.getGlobalBounds().height);
    return;
}

#endif

编辑:它适用于内联关键字

在 C++ 中,一个定义规则 (ODR) 指出 object 和 non-inline 函数在整个程序中不能有多个定义,模板和类型不能有多个定义按翻译单位。正如 cppreference 根据一个定义规则所述:

One and only one definition of every non-inline function or variable that is odr-used (see below) is required to appear in the entire program (including any standard and user-defined libraries). The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined.

这就是为什么在不内联函数时会出现多重定义 link 错误的原因。这些函数包含(按字面意思复制)到实现文件中。 header 守卫不会阻止这种情况,因为文件是单独包含的。所以你违反了 ODR,因为具有外部 linkage 的同一个函数被定义了多次。

当你内联函数时,每个翻译单元(实现文件+它的所有包含文件)都会得到它自己的函数副本。由于 link 和 link 文件 object 中的 inline 关键字,这不会被视为违反 ODR。这就是 inline 的特别之处:它告诉 linker 同一函数的多个定义不是错误。

您有两个选择:

  • 像您所做的那样内联函数;
  • 将函数声明放在一个 header 文件中,将定义放在一个 cpp 文件中

我会选择第一个选项,因为函数很短而且不那么复杂。

一年后,我才知道inline关键字已经失去了原来的意义。它曾经被用来充当预处理指令,有点像,然后将函数复制粘贴到调用它的任何地方,而不是对所有正在进行的函数调用执行跳转指令。如果你调用你的函数 100 万次,它会快一点,但很明显,编译器现在自己做。内联现在的意思是'是的,这个东西可以定义多次,没关系'。