我可以编写没有标题的C++代码(重复的函数声明)吗?

the*_*eck 56 c++ header header-files

有没有办法不必编写两次函数声明(头文件),并且在编译时仍然保持相同的可伸缩性,调试的清晰度和在C++中编程时的设计灵活性?

Ric*_*den 57

使用Lzz.它需要一个文件,并为您自动创建.h和.cpp,并在正确的位置显示所有声明/定义.

Lzz非常强大,可以处理99%的完整C++语法,包括模板,专业化等等.

更新150120:

较新的C++ '11/14语法只能在Lzz函数体中使用.


rix*_*rrr 37

当我开始写C时,我也有同感,所以我也研究了这个.答案是,是的,有可能,不,你不想.

首先是的.

在GCC中,您可以这样做:

// foo.cph

void foo();

#if __INCLUDE_LEVEL__ == 0
void foo() {
   printf("Hello World!\n");
}
#endif
Run Code Online (Sandbox Code Playgroud)

这具有预期的效果:您将标题和源都合并到一个文件中,该文件既可以包含也可以链接.

然后是否:

这仅在编译器可以访问整个源时才有效.在编写要分发但保持闭源的库时,不能使用此技巧.您要么分发完整的.cph文件,要么必须编写一个单独的.h文件来与.lib一起使用.虽然也许您可以使用宏预处理器自动生成它.但它会变得毛茸茸.

理由#2为什么你不想要这个,这可能是最好的一个:编译速度.通常,只有在文件本身发生更改或其包含的任何文件发生更改时,才需要重新编译C源文件.

  • C文件可以经常更改,但更改只涉及重新编译更改的一个文件.
  • 头文件定义接口,因此它们不应经常更改.但是,当它们执行时,它们会触发重新编译包含它们的每个源文件.

当所有文件都是头文件和源文件的组合时,每次更改都会触发重新编译所有源文件.C++现在还不知道它的快速编译时间,想象一下每次必须重新编译整个项目时会发生什么.然后将其推断为具有复杂依赖性的数百个源文件的项目......

  • 头文件在C中工作得非常好,我同意这一点.但在C++中,它们并不总是有意义的.例如,在类声明中声明私有方法没有多大意义.您应该能够根据需要定义尽可能多的私有方法,而不会影响外部文件. (3认同)

ojr*_*rac 27

对不起,但是没有用于消除C++标题的"最佳实践":这是一个坏主意,期间.如果你恨他们那么多,你有三个选择:

  • 熟悉C++内部和您正在使用的任何编译器; 你会遇到与普通C++开发人员不同的问题,你可能需要在没有很多帮助的情况下解决它们.
  • 选择一种可以"正确"使用的语言而不会感到沮丧
  • 获取一个工具来为您生成它们; 你仍然会有标题,但你节省了一些打字工作

  • 有道理.我将承认第三种选择 - 感谢您解释这个缺陷. (6认同)
  • 我认为它可能被低估了,因为它是非特定的(例如"什么是"地狱般的问题"),因此无用.而且,就像你指出的那样,它是一个_opinion_因此是主观的,这在这个社区中通常是无益的. (3认同)
  • -1 此处的答案中提到的 lzz-tool 解决了“提问者”隐含的问题,而没有您描述的负面影响(因为 lzz-tool 确实使用标题。您不必实际编写它们)。这使得这个答案没有建设性。对不起。 (2认同)
  • @ojrac,没问题.:)我认为C++(头文件以及其他东西)的部分问题在于这些功能都需要严格的规则才能使它们正确.例如,如果你没有练习PIMPL习语,标题很痛苦,但是使用PIMPL习语,它们类似于Ada规范,这些规范实际上很有价值.与大多数语言不同,C++会让你做错事(例如,在头文件中发布私有方法),直到有人解释最佳实践/解决方法 - 即使这样,你也要坚持他们 - 你将没有得到编译器的帮助. (2认同)

Dan*_*nas 10

Pedro Guerreiro 在他的文章" 简单支持C++合同设计"中说:

通常,C++类有两个文件:头文件和定义文件.我们应该在哪里编写断言:在头文件中,因为断言是规范的?或者在定义文件中,因为它们是可执行的?或两者兼而有之,冒着不一致的风险(和重复工作)?我们建议,相反,我们抛弃了传统的风格,并废除定义文件,仅使用头文件,好像所有职能联定义,非常像Java和艾菲尔做.

这是C++正常性的一个巨大变化,它可能会在一开始就扼杀这一努力.另一方面,为每个类维护两个文件是如此尴尬,迟早会出现一个隐藏C++开发环境的环境,让我们专注于我们的课程,而不必担心它们的存储位置.

那是2001年.我同意了.现在是2009年,现在仍然没有"隐藏我们的开发环境,让我们专注于我们的课程".相反,长编译时间是常态.


注意:上面的链接现在似乎已经死了.这是对该出版物的完整参考,因为它出现在作者网站的出版物部分:

Pedro Guerreiro,简单支持C++合同设计,TOOLS USA 2001,Proceedings,24-34页,IEEE,2001.

  • 根据我的经验,C#编译速度比C++快,并且依赖性检查(至少在VS2008中)要好得多. (8认同)
  • @TED - 是的,这是正确的.但Visual Studio比C++编译C#库要快得多,它并不重要.此外,在开发新应用程序时,无论如何都要不断修改头文件,因此即使使用C++,您也会进行大量编译.我没有引用的基准,但我估计C#编译比C++快10-20倍.此外,Visual Studio实时进行C#语法编译(如拼写检查程序),因此在完成之前很少需要点击编译按钮. (2认同)
  • 这就是为什么你只是构建一个自动为你分离事物的系统。现在是 2013 年了。C++ 已经有几十年的历史了,工具还没有进步那么多吗?这就是我们成为工程师的原因!让事情自动化! (2认同)

Nil*_*nck 8

没有实用的方法来绕过标题.您唯一能做的就是将所有代码放入一个大的c ++文件中.这将最终陷入难以控制的混乱,所以请不要这样做.

目前C++头文件是一个非常邪恶的东西.我不喜欢他们,但没有办法解决他们.我很乐意看到有关这个问题的一些改进和新想法.

顺便说一句 - 一旦你习惯了它就不再那么糟了.. C++(以及任何其他语言)都有更多令人讨厌的东西.


T.E*_*.D. 8

我所看到的有些人喜欢你在标题中写下所有内容.这给你想要的属性只需要编写一次方法配置文件.

就个人而言,我认为有很好的理由说明为什么分离声明和定义更好,但如果这让你感到困扰,那就有办法做你想做的事.


Căt*_*tiș 5

你必须写两次函数声明,实际上(一次在头文件中,一次在实现文件中).函数的定义(AKA实现)将在实现文件中写入一次.

您可以在头文件中编写所有代码(它实际上是C++中通用编程中非常常用的实践),但这意味着包含该头的每个C/CPP文件都意味着从这些头文件重新编译实现.

如果您正在考虑使用类似于C#或Java的系统,那么在C++中是不可能的.

  • 好吧,真的吗?甚至*不可能*?这就是未来!其他所有语言都可以一次动态地重新编译源代码的一小部分。在自动重新生成标头后,编译器进行一些基本文件检查并仅重新链接已更改的文件有多难?Java一直这样做。见鬼,Android 会在您编码时在后台从 XML 文件生成 Java 代码 - 所以不要告诉我这在 C++ 中是不可能的。工具不可能和 30 年前一样,对吧? (2认同)

0sc*_*car 5

有头文件生成软件.我从来没有用过它,但它可能值得研究.例如,看看mkhdr!它应该扫描C和C++文件并生成适当的头文件.

(但是,正如理查德指出的那样,这似乎限制了你使用某些C++功能.请参阅理查德的答案,而不是在这个帖子中.)