[英]How to order functions in C++?
我不知道如何在C ++中订购我的函数。 在C中,我只是放置了一个函数,该函数使用该函数下面的另一个函数,尽可能接近 - 这很常见。 像这样:
void bar()
{
}
void foo()
{
bar();
}
但是,在C ++中,有几种类型的函数:
我目前正在使我的函数顺序依赖于它们在.hpp文件中的排序方式,例如:
class Foo_bar {
public:
Foo_bar();
void foo();
private:
int some_member;
void bar();
但是现在,如果构造函数使用foo()或bar(),它们将位于源文件中的构造函数下方 ,与我通常的顺序不一致。 我当然可以重新排序我的标题以考虑到这一点:
class Foo_bar {
private:
int some_member;
void bar();
public:
void foo();
Foo_bar();
但我认为那是一团糟。
此外,在Java中,与我的第一个示例相反似乎很常见:
void foo()
{
bar();
}
void bar()
{
}
这可能是由于OOP中常见的自上而下的思维,与程序/函数式编程中常见的自下而上的思维形成鲜明对比。 但是,对于没有原型的自由函数,这种自上而下的风格是不可能的。
甚至可以以一致的方式在C ++中命令函数吗?
这是可能的。 你必须使用前瞻声明 。
在定义函数之前声明一个函数,即使之前定义了函数,其他函数也会看到它没有问题。
所以,你应该能够用C ++做到这一点:
void bar(); // forward declaration; note that function bar isn't defined yet
void foo()
{
bar(); // foo knows that bar is declared, so it will search for bar's definition
}
void bar() // here bar is defined, so foo will use this when needed
{
}
实际上这是一个非常好的问题,因为可读性会影响到你之后阅读代码的人。
有3种人会阅读课程代码:
出于这个原因,我尝试订购标题,以便任何用户可以在他得到他想要的东西后停止,这意味着:
class Foo
{
public:
// types
// static methods
// methods (usually constructors,
// then simple accessors,
// then more complicated stuff)
protected:
// same pattern
private:
// same pattern
// attributes
};
// Free functions about this class
// Implementation of inline / template methods
有时我需要事先声明一些类型,即使它们是私有的,但这种情况很少见。 这种排序的目的是绝对减少读者在得到他想要的东西之前必须阅读的内容量(并且在不得不打断自己查看代码之前停止阅读并回到他正在做的事情)。
然后,关于“帮助”方法,它取决于代码的类型:
如果某些代码可能需要很多帮助程序,我倾向于在源目录中创建一个专用的头文件,给出以下结构:
include/
foo.hpp
src/
fooImpl.hpp --> #include "foo.hpp"
foo.cpp --> #include "fooImpl.hpp"
为了向读者提供声明列表,因为浏览声明列表比从定义列表中提取声明更容易,无论缩进和样式如何。
当然,总是为了让它更容易,我总是同样地命令声明列表和定义列表......
你在头文件中声明了这个类,对吧? 并在一个单独的文件中实现其中的大部分? 如果你只是在实现文件中而不是在头文件中实现构造函数,我认为你不会遇到你提到的问题(因为在看到构造函数调用foo()
或bar()
之前会看到整个头文件bar()
。
在C ++中排序自由函数遵循与您提到的相同的规则,但是像darioo所说的那样,您可以转发声明它们并以您想要的任何方式排序函数定义。 这也是首选方法:在头文件中声明所有内容,并将所有定义放在源文件中。 但是,对于模板,这是不可能的,没有一些非平凡和非一般的反模板解决方法。
在类中,事情通常是不同的,因为几乎没有在标题中完全实现类的情况,因此当您在源文件中定义函数时,始终会读取声明。
我通常在“功能”中订购功能,例如。 getter和setter,构造函数/析构函数(如果可能的话)。
关于重新排序类定义中的函数的问题是不正确的,正如C ++ 03标准中的以下两个引号所阐明的那样。
$ 9.2 / 2-“类在类别说明符的结束时被认为是一个完全定义的对象类型(3.9)(或完整类型)。 在类成员规范中,该类在函数体内被认为是完整的,默认参数和构造函数ctor-initializers(包括嵌套类中的这类东西)。否则它在自己的类成员规范中被认为是不完整的。“
和
$ 3.4.1 / 8 - “在函数的declaratorid29之后的类X的成员函数(9.3)的定义中使用的名称应以下列方式之一声明:
- 在其使用的块中或在封闭块(6.3)中使用之前,或
- 应为X类成员或X(10.2)基类的成员,或
- 如果X是类Y(9.7)的嵌套类,则应该是Y的成员,或者应该是Y的基类的成员(此查找依次应用于Y的封闭类,从最内层的封闭类开始) ,30)或
- 如果X是本地类(9.8)或是本地类的嵌套类,则在包含X类定义的块中定义类X之前,或者
- 如果X是名称空间N的成员,或者是作为N的成员的类的嵌套类,或者是作为N的成员的函数的本地类中的本地类或嵌套类,则成员函数定义,在名称空间N中或在N的封闭名称空间之一中。
作为一般规则,在C ++中,函数定义必须在其使用时可见。 唯一的例外是类成员函数的情况,如上面的引号所示。
因此,这意味着构造函数调用的类成员函数不需要在构造函数的词法之前定义。
就个人而言,我喜欢在文件顶部附近看到将从别处引用的内容(人们需要经常查找/阅读)。 一旦稳定,有希望被遗忘的内部构件将留待以后使用。
但是存在不一致之处。 例如,在一个类中,它意味着先将公共内容放入私有内部。 但是类的默认可见性(你自然得到的)是私有的,并且(特别是如果我有内联样式方法)我通常会将任何私有数据放在前面。 内联样式方法在定义之前引用成员变量甚至可能是错误的 - 抱歉,我遇到了临时内存问题。
但基本上,主要是将事物放在一起而不是相似或逻辑相关。 begin方法将与end方法相邻,与Step_To_Prev方法相邻的Step_To_Next方法等。分组是相似的目的,类似的参数,并且通常一起使用都是好的。
什么叫做主要是一个实现细节,所以不一定要强调你的库用户会读取的头文件 - 尽管在实现代码中可能会有所不同。 正如其他人所指出的那样,前瞻性声明允许一些自由。
最重要的是(1)采用一致的风格,(2)不要过于担心模糊的情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.