通过包含访问函数与声明静态

时间:2013-01-08 08:58:08

标签: c++ oop static include

我想要包含在另一个cpp文件中的头文件。我想知道如果我写这样的头文件有什么区别,

#include <iostream>
#include <string>
using namespace std;

string ret()
{
return "called";
}

===================================

#include <iostream>
#include <string>
using namespace std;

static string ret()
{
return "called";
}

无论如何我都可以访问ret()功能!那么,静态的用途是什么?

4 个答案:

答案 0 :(得分:5)

这是一个非常邪恶的头文件,你正在展示。

  1. 从不using namespace std;放入头文件中。这会强制包括标头在内的任何人在全局命名空间中拥有所有std

  2. 使用某种形式的包含警卫。

  3. static使该函数在包含它的.cpp之外不可见。这意味着包含标题的每个.cpp都有自己的函数副本。只有在您特别需要此行为时,才应使用static(非成员)函数。

  4. 如果不使用static,则应将定义从标题移动到源文件中(如果要将其定义一次),或者声明函数inline(如果可能的话,它的代码将在每个呼叫站点上内联。如果不同时执行这些操作,如果将标题包含在多个源文件中,则会出现多个定义错误。

答案 1 :(得分:4)

第一个头文件定义了一个名为ret的函数,在包含它的每个翻译单元中都有外部链接。如果在同一程序中链接了多个此类TU,则这是不正确的。

第二个头文件定义了一个名为ret的函数,在包含它的每个翻译单元中都有内部链接。这意味着每个TU都有自己的函数私有副本(具有不同的地址),无论有多少链接在一起。

使用头文件共享代码有三种正确的方法:

  • 具有内部链接的功能(如在第二个标题中,或在C ++ 11中,通过将其放在无名空间中)。
  • 内联函数与外部链接(将static替换为inline)。 inline的含义是虽然程序中只有一个函数副本,但每个使用该函数的TU都包含它的定义。
  • 在标头中声明该函数,并在其中定义一个.cpp文件(例如ret.cpp)。

在C ++ 03中有第四种方式:

  • 在无名空间中使用外部链接的功能

我相信这在C ++ 11中仍然可用,但在C ++ 11中,无名空间中的函数默认具有内部链接。我不知道在C ++ 11中使用无名空间中的函数有任何外部链接。因此,就函数而言,无名空间是提供函数内部链接的好方法。

您使用哪一个取决于您的需求。第三个选项意味着你可以在不重新编译调用代码的情况下更改函数的定义,尽管除非函数在dll中,否则你仍然需要重新链接可执行文件。

前两个(staticinline)在以下情况下的行为不同:

  • 该函数包含static局部变量
  • 将函数指针与不同TU中的ret进行比较,
  • 检查可执行文件大小或符号表,
  • 函数的定义在不同的TU中是不同的(可能是由于不同的#defines),如果函数具有外部链接而不是内部链接则禁止该函数。

否则它们大致相同。

根据标准,inline也提示编译器应优化对该函数的调用以便快速执行(实际上,这意味着内联调用站点的代码)。大多数编译器大多数时候都忽略了这个提示。如果他们认为它是一个很好的内联候选者,他们会愉快地内联static但非inline函数,如果他们评估它是inline函数,他们会很乐意避免内联的不良候选人。

答案 2 :(得分:2)

使用标题保护。

不要在头文件中使用“using namespace”。 (实际上,不要在头文件中使用“using”。使用完全限定的标识符。)

使用声明函数的标头,而不是定义它们。您希望ret()的代码仅出现在生成的可执行文件中一次。您可以通过将ret()的定义(代码)放在.cpp文件中来实现此目的。 一个 .cpp文件,而不是多个(通过包含定义)。

头文件列出函数ret()声明,以便其他代码“知道”该函数存在,它采用哪个参数以及它返回的内容。

答案 3 :(得分:1)

如果在头文件中将c ++方法定义为static,则每个转换单元(包含该头文件的每个.cpp文件)将具有这些静态方法的不同版本 - 它们将不具有相同的地址空间。 因此,程序的大小会不必要地增加。

另外,为了清楚起见:

仅在.cpp文件中将方法定义为static意味着该方法具有静态链接,并且只能从同一.cpp文件中的其他方法访问。