2010-12-08 51 views
3

根据我的老师的实现,这是不好的做法,编写用户定义函数是这样的:宣言和功能

int DoubleNumber(int Number) 
{ 
    return Number * 2; 
} 

int main() 
{ 
    cout << DoubleNumber(8); 
} 

相反,他说要总是使用前向声明,即使功能别吨需要对方的任何知识:

int DoubleNumber(int Number); // Forward declaration. 

int main() 
{ 
    cout << DoubleNumber(8); 
} 

int DoubleNumber(int Number) // Implementation. 
{ 
    return Number * 2; 
} 

我发现这非常奇怪,因为他做了告诉我们是多么重要的是,向前声明和实现是一个点正好相同或你会得到错误。如果这是件大事,为什么不把它放在main()以上呢?

那么,同时申报和实施真的是不好的做法吗?它甚至重要吗?

+2

老师面临的问题是他们很少有足够的时间来练习他们所教的科目,而编程就是其中一个领域,如果你不练习它,你就会失去它。 – 2010-12-08 20:03:05

+0

如果您的函数要在编译单元之外使用,则无论如何您都需要在* .h文件中声明它们。同样,非平凡类方法将在类定义中分别声明。与上述用法相比,IME仅限于内部非内联函数,因此从广义上讲,它并不重要。 – comingstorm 2010-12-08 20:19:58

回答

9

如果您没有声明前向声明(“原型”),那么您需要确保所有函数都发生在依赖于它们的函数之前,即按照调用图的相反顺序。对于上面的一个简单示例来说,这很好,但是对于更现实的任何事情(如果调用图中存在任何循环的话,在某些情况下不可能),这是完全痛苦的。

+7

我发现重新排序功能比保持声明和定义不同步更麻烦。它还有助于说明设计的层次结构 - 帮助者在顶部,然后是更重要的东西,然后是main()在底部。尽管如此,似乎有些人更喜欢相反的顺序。 – 2010-12-08 19:12:17

+0

看起来像在硬核“干净的代码”中(即将几乎所有东西放在函数中),这些函数会更加痛苦,特别是在大型项目中。再一次,保持原型和实现同步也似乎是一个大项目的烦人。 – Maxpm 2010-12-08 19:29:58

+0

@Karl:如果你的函数是通过头文件公开的,那么无论如何你都必须做“保持同步”。关于个人对订单的偏好,我的帮手应该放在底部,因为它们是最没有趣味的! (至少从“了解结构”的角度来看) – 2010-12-08 20:44:49

6

你的老师的政策是可怕的恕我直言。只有在真正需要时才使用前向声明。这样,他们的存在证明了他们的必要性,这为读者提供了有用的文档(即,函数之间可能存在相互递归)。当然,你需要在头文件中进行前向声明;这就是他们的目标。

2

问你的老师为什么他建议这样做;)无论如何,在我看来,这不是坏习惯,在大多数情况下,它甚至都不重要。预先声明所有函数的最大优点是您可以高级地了解代码的功能。

4

在我的第一个编程课上,老师也强调了这一点。我不确定在实际软件中有这样一个简单情况的好处。

但是,它确实准备使用头文件,如果你还没有覆盖。在典型情况下,您将拥有一个头文件custom-math.h和源文件custom-math.cpp,其中custom-math.h包含前向声明和custom-math.cpp的实现。这样做可能会在仅在大型项目中对函数实现进行修改时显着增加编译时间。这也是将程序分成“逻辑”功能组和/或类组的一种便捷方式。

如果你打算把其他功能,在同一个文件main(),然后你做什么可能取决于你的个人喜好。有些人更喜欢靠近顶部的main()来马上进入程序逻辑。在这种情况下,向前声明你的功能。

1

传统上你会把所有的原型都放在一个头文件中,这样他们就可以被其他源文件使用 - 或者至少你会把你想要公开的文件放在.h文件中。

至于没有必要的代码,将所有的文件级声明放在最上面(变量和函数)是有意义的,因为这意味着你可以随意移动函数而不必担心关于它。更何况,我可以立即看到文件中的每个功能。但这样的:

void Func1() { ... } 
... 
void Func2() { ... } 
... 
void Func3() { ... } 
... 
int main() { Func1(); Func2(); Func3(); return 0; } 

这 - 这就是说,一些不连贯的功能全部由被称为主() - 是一种很常见的文件,这是完全合理的放弃声明。

3

Karl Knecthel写道:“只有在真正需要时才使用前向声明,这样,他们的存在证明了他们的必要性,这为读者提供了有用的文档(即函数之间可能存在相互递归)。和恕我直言,这是很好的建议。

奥利查尔斯沃思谈到排序函数的“完全痛苦”,以便可以在没有前向声明的情况下调用它们。这不是我的经历,我无法想象这种痛苦/问题是如何实现的。我怀疑那里存在PEBCAK问题。

对所有函数使用前向声明的做法不会为您节省PEBCAK问题,但它们确实引入了不必要的维护工作,并且不需要更多的代码来关联,而且它们使得更加不清楚哪些函数确实需要前向声明。

如果您已经到了前向声明可以帮助您一眼看到函数签名的地步,那么当被迫使用一些非常简单的编辑器时,应该采取两个操作:(1)重构代码,以及(2)切换到更好的编辑器。

干杯&心连心,

1

毯子规则很少是正确的。您通常会通过头文件中的原型公开api公开的API。其余的函数可能会在cpp文件中的匿名命名空间中。如果在实现中多次调用它们,那么在顶部提供原型是有意义的,否则使用它们的每个函数都必须在调用函数之前提供原型。同时,如果在cpp文件中多次使用某个函数,这可能表明它足够通用,可以移动到通用api。如果这些功能没有在整个地方使用,最好提供尽可能有限的曝光,即声明和定义它们靠近它们被呼叫的地方。

0

就我个人而言,我只想转发客户端代码需要知道的任何内容(即在类头中)。任何对类实现本地化的东西(比如帮助函数)都应该在使用之前定义。

当然,在一天结束时,大多数情况下,它归结为您的项目遵循的个人偏好或编码标准。

6

我认为你的老师是一位老C程序员。

如果你编写了一个没有前向声明的C程序和一个名为稍后在文件中声明的另一个函数(或者在另一个编译单元中),编译器不会抱怨,而是默默地假装知道原型应该是什么。

如果您不知道您的编译器是否正确传递参数,那么调试是非常可怕的。因此,总是宣布所有功能是一个很好的防守策略;如果声明与实现不匹配,至少编译器可能会引发错误。

C编译器和工具变得更好了(我希望)。调用一个未知的函数仍然没有错误,但是例如GCC默认情况下会提示警告。

但在C++中,您无法调用尚未声明或定义的函数。因此,C++程序员不必担心前向声明。