当前位置:  开发笔记 > 编程语言 > 正文

在C++中分离声明和定义有什么优缺点?

如何解决《在C++中分离声明和定义有什么优缺点?》经验,为你挑选了2个好方法。

在C++中,函数的声明和定义,变量和常量可以像这样分开:

function someFunc();

function someFunc()
{
  //Implementation.
}

实际上,在类的定义中,通常就是这种情况.通常使用.h文件中的成员声明类,然后在相应的.C文件中定义这些类.

这种方法有哪些优缺点?



1> philsquared..:

从历史上看,这是为了帮助编译器.在使用它们之前你必须给它一个名单 - 无论是实际用法,还是前向声明(C的默认功能原型除外).

现代语言的现代编译器表明这不再是必需品,因此这里的C&C++(以及Objective-C,可能还有其他语法)语法是组织上的包袱.事实上,这是C++的一大问题,即使添加适当的模块系统也无法解决.

缺点是:许多重度嵌套的包含文件(我之前跟踪过包含树,它们非常庞大)以及声明和定义之间的冗余 - 所有这些都导致更长的编码时间和更长的编译时间(比较可比较的C++和C++之间的编译时间) C#项目?这是差异的原因之一).必须为您提供的任何组件的用户提供头文件.ODR违规的可能性.依赖于预处理器(许多现代语言不需要预处理器步骤),这使您的代码更加脆弱,并且难以分析工具.

优点:没什么.你可能会争辩说你得到了一个在一个地方组合在一起的函数名列表以供记录 - 但是现在大多数IDE都有某种代码折叠能力,而且任何大小的项目都应该使用doc生成器(例如doxygen).使用更清晰,无预处理器,基于模块的语法,工具更容易遵循您的代码并提供更多,因此我认为这种"优势"只是没有实际意义.



2> 小智..:

这是C/C++编译器如何工作的人工制品.

当源文件被编译时,预处理器将每个#include-statement替换为包含文件的内容.之后,编译器才会尝试解释此连接的结果.

然后编译器从头到尾检查结果,尝试验证每个语句.如果一行代码调用之前未定义的函数,它将放弃.

但是,当涉及到相互递归的函数调用时,存在一个问题:

void foo()
{
  bar();
}

void bar()
{
  foo();
}

在这里,foo不会编译为bar未知.如果你切换两个函数,bar将无法编译为foo未知.

但是,如果您单独声明和定义,则可以根据需要订购函数:

void foo();
void bar();

void foo()
{
  bar();
}

void bar()
{
  foo();
}

在这里,当编译器处理foo它已经知道被调用的函数的签名时bar,并且很高兴.

当然,编译器可以以不同的方式工作,但这就是它们在C,C++和某种程度上的Objective-C中的工作方式.

缺点:

没有直接.如果你正在使用C/C++,那么这是做事的最佳方式.如果你有一个语言/编译器可供选择,那么也许你可以选择一个不是问题的地方.将声明拆分为头文件时唯一要考虑的是避免相互递归的#include-statements - 但这就是包含防护的内容.

好处:

编译速度:由于所有包含的文件被连接在一起然后被解析,减少包含文件中代码的数量和复杂性缩短编译时间.

避免代码重复/内联:如果在头文件中完全定义了一个函数,那么包含此头文件并引用此函数的每个目标文件都将包含它自己的该函数版本.作为旁注,如果内联,则需要将完整定义放入头文件(在大多数编译器上).

封装/清晰度:一个定义良好的类/函数集以及一些文档应该足以让其他开发人员使用您的代码.(理想情况下)他们不需要理解代码是如何工作的 - 那么为什么要求他们筛选代码呢?(反过来说,当需要时,它们对于他们访问实现可能是有用的,当然).

当然,如果你根本不想公开一个函数,你通常仍然可以选择在实现文件而不是标题中完全定义它.

推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有