flu*_*els 9 c++ language-design declaration definition
在C++中,函数的声明和定义,变量和常量可以像这样分开:
function someFunc();
function someFunc()
{
//Implementation.
}
Run Code Online (Sandbox Code Playgroud)
实际上,在类的定义中,通常就是这种情况.通常使用.h文件中的成员声明类,然后在相应的.C文件中定义这些类.
这种方法有哪些优缺点?
phi*_*red 14
从历史上看,这是为了帮助编译器.在使用它们之前你必须给它一个名单 - 无论是实际用法,还是前向声明(C的默认功能原型除外).
现代语言的现代编译器表明这不再是必需品,因此这里的C&C++(以及Objective-C,可能还有其他语法)语法是组织上的包袱.事实上,这是C++的一大问题,即使添加适当的模块系统也无法解决.
缺点是:许多重度嵌套的包含文件(我之前跟踪过包含树,它们非常庞大)以及声明和定义之间的冗余 - 所有这些都导致更长的编码时间和更长的编译时间(比较可比较的C++和C++之间的编译时间) C#项目?这是差异的原因之一).必须为您提供的任何组件的用户提供头文件.ODR违规的可能性.依赖于预处理器(许多现代语言不需要预处理器步骤),这使您的代码更加脆弱,并且难以分析工具.
优点:没什么.你可能会争辩说你得到了一个在一个地方组合在一起的函数名列表以供记录 - 但是现在大多数IDE都有某种代码折叠能力,而且任何大小的项目都应该使用doc生成器(例如doxygen).使用更清晰,无预处理器,基于模块的语法,工具更容易遵循您的代码并提供更多,因此我认为这种"优势"只是没有实际意义.
小智 11
这是C/C++编译器如何工作的人工制品.
当源文件被编译时,预处理器将每个#include-statement替换为包含文件的内容.之后,编译器才会尝试解释此连接的结果.
然后编译器从头到尾检查结果,尝试验证每个语句.如果一行代码调用之前未定义的函数,它将放弃.
但是,当涉及到相互递归的函数调用时,存在一个问题:
void foo()
{
bar();
}
void bar()
{
foo();
}
Run Code Online (Sandbox Code Playgroud)
在这里,foo不会编译为bar未知.如果你切换两个函数,bar将无法编译为foo未知.
但是,如果您单独声明和定义,则可以根据需要订购函数:
void foo();
void bar();
void foo()
{
bar();
}
void bar()
{
foo();
}
Run Code Online (Sandbox Code Playgroud)
在这里,当编译器处理foo它已经知道被调用的函数的签名时bar,并且很高兴.
当然,编译器可以以不同的方式工作,但这就是它们在C,C++和某种程度上的Objective-C中的工作方式.
缺点:
没有直接.如果你正在使用C/C++,那么这是做事的最佳方式.如果你有一个语言/编译器可供选择,那么也许你可以选择一个不是问题的地方.将声明拆分为头文件时唯一要考虑的是避免相互递归的#include-statements - 但这就是包含防护的内容.
好处:
当然,如果你根本不想公开一个函数,你通常仍然可以选择在实现文件而不是标题中完全定义它.
| 归档时间: |
|
| 查看次数: |
6126 次 |
| 最近记录: |