将函数定义放在头文件中

时间:2011-10-20 09:37:51

标签: c++ static namespaces inline header-files

如果要将函数定义放在头文件中,可能会出现三种不同的解决方案:

  1. 将该功能标记为inline
  2. 将该功能标记为static
  3. 将该函数放入匿名命名空间
  4. (直到最近,我甚至都没有意识到#1。)那么这些解决方案有什么不同之处,何时我更喜欢哪种?我是在仅限标题的世界中,所以我真的需要头文件中的定义。

4 个答案:

答案 0 :(得分:15)

static和未命名的命名空间版本最终是相同的:每个翻译单元将包含它自己的函数版本,这意味着给定一个静态函数f,指针{{1每个翻译单元会有所不同,程序将包含N个不同版本的&f(二进制代码中的代码更多)。

这是在标头中提供 a 功能的正确方法,它将提供 N 不同(完全相同)的功能。如果函数包含f个本地符号,则会有 N 不同的static局部变量...

编辑:为了使其更加明确:如果你想要的是在不破坏一个定义规则的情况下在标题中提供函数的定义,那么正确的方法是使函数{{ 1}}。

答案 1 :(得分:4)

据我所知,只有inline和模板函数可以在头文件中定义。

不推荐使用

static函数,而应使用未命名的命名空间中定义的函数(参见7.3.1.1 p2)。当您在标头中的未命名命名空间中定义函数时,包含该标头(直接或间接)的每个源代码都将具有唯一的定义(请参阅7.3.1.1 p1)。因此,不应在头文件中的未命名命名空间中定义函数(仅在源文件中)。

引用的标准来自c ++ 03标准。

编辑:

下一个示例演示了为什么函数和变量不应该在头文件中定义为未命名的命名空间:

ops.hpp 包含:

#ifndef OPS_HPP
#define OPS_HPP
namespace
{
int a;
}
#endif

dk1.hpp 包含:

#ifndef DK1_HPP
#define DK1_HPP
void setValue();
void printValue();
#endif

dk1.cpp 包含:

#include "dk1.hpp"
#include "ops.hpp"
#include <iostream>

void setValue()
{
    a=5;
}
void printValue()
{
    std::cout<<a<<std::endl;
}

dk.cpp 包含:

#include "dk1.hpp"
#include "ops.hpp"
#include <iostream>

int main()
{
    // set and print a
    setValue();
    printValue();

    // set and print it again
    a = 22;
    std::cout<<a<<std::endl;

    // print it again
    printValue();
}

像这样编译:

g++ -ansi -pedantic -Wall -Wextra dk.cpp dk1.cpp

和输出:

5
22
5

对于源文件adk1.cpp

,变量dk.cpp不同

答案 2 :(得分:0)

static函数(相当于匿名命名空间)为每个TU接收不同的副本。如果函数是可重入的,那么它基本相同(某些编译器可能具有汇编级差异),但如果不是,则每个TU将具有不同的静态数据。内联函数是折叠的 - 也就是说,它们每个TU只有一个静态数据副本。

答案 3 :(得分:0)

您可以考虑将方法包装在类而不是名称空间中。将这些方法声明为静态方法,并删除类的构造函数以强调这不是要实例化的对象。

struct FooNamespace
{
    FooNamespace() = delete;

    static FooMethod1() {
        ...
    }
    static FooMethod2() {
        ...
    }

};

您得到的一般行为与仅属于单个实现的属于命名空间的行为相同。