为什么在 C++ 中需要分别声明和定义函数?

12

我刚开始学习C++,我看到函数通常是分别声明和定义的,例如:

// Declaration
void sayhi(std::string name);

// Definition
void sayhi(std::string name) {
  std::cout << "Hello, " << name;
}

我尝试搜索,但大多数问题都是关于类的情况,而我更一般的问题是,为什么我们要将它们分开?有什么好处吗?


在最初使用C的古老计算机上必须这样做。在新的编程语言中没有任何好理由这样做。 - Boann
3个回答

11
同一个函数可以在不同的编译单元中使用。
如果该函数被定义在头文件中,且不是内联函数或具有内部链接的函数,则只要该头文件被包含在多个编译单元中,就会破坏“一个定义规则”(ODR)。
因此,通常这样的函数在头文件中声明,在一些模块中定义。这样,使用该头文件的不同编译单元将看到函数声明,并且函数只会被定义一次。
如果程序仅由一个编译单元组成,则没有必要分别声明和定义一个函数,因为函数定义同时也是其声明。

感谢您的评论和耐心。我需要更多的经验来理解这一切,但是我非常感激您的时间和帮助。 - jshji

9

为什么我们要把它们分开?

我们并不是这样做。
只要我们能够摆脱它,因为它违反了DRY,引入了(只有部分检查的)重复。

问题在于C来自于一系列单通编译器,虽然C++通过模板和返回类型推导添加了很多东西,但它并没有完全扭转这个事实。

因此,如果你想在定义之前使用一个函数,你必须提供一个前向声明。

如果你想对代码的某些部分进行分离编译,这通常是明智的,因为可以缩短编译时间并能够在其他语言中使用库(静态或非静态),而不需要源文件或以其他选项编译,那么你需要一些方式告诉编译器会有哪些内容存在。

头文件是这些前向声明、常量声明、内联函数(内联函数必须在使用它们的每个翻译单元中定义)、类型定义等的集合。
一般来说,实现文件首先包含相应的头文件以验证它们是否有效且自包含。

承认,C++20引入的模块系统是一个新的变化,进一步减少了前向声明的需求。

这非常有帮助。我肯定需要更多的经验才能完全理解你的解释,但我很感激你的赞扬。谢谢。 - jshji
直白地说,我们通常不会将函数声明和定义分开,因为这会使脚本变得冗长,除非程序仍处于开发阶段。 - Nader Belal
只要不是必要的,将声明与定义分开只会增加额外负担。WIP 与此关系不大。 - Deduplicator
什么时候可能需要这个? - Nader Belal
1
@NaderBelal 互递归和头文件。 - Deduplicator

2
头文件是一个方便的机制,可以从多个翻译单元访问变量声明和函数原型。
#include <header> 

让您可以将这些内容包含在许多类中。因此,使代码更具可重用性。


1
可以在头文件中实现所有内容,这样就没有声明和定义的分离。我认为这个答案并没有回答问题。 - Fureeish
这个问题的最佳答案的要点对于函数和类一样适用,如果你想补充Morpheus的回答。 - Federico klez Culloca
1
你的回答提到了将代码分离到可以被包含的头文件中。这与声明和定义的分离没有任何关系,例如.hpp.cpp文件。正如我所说 - 有些代码可以移动到头文件中(就像你在回答中所说的那样),但仍然不能分离声明和定义,这似乎是问题的核心所在。 - Fureeish
这就是我的意思。我所指的是帮助确保您不会不必要地反复使用代码,这另一种说法是避免重复。 - user12053089
@Morpheus 没错。代码复用很好!通过重复使用代码,您可以避免重复。 - Federico klez Culloca
显示剩余5条评论

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