我应该如何订购一个C ++类的成员?
拥有所有的私人成员,那么所有的受保护的,那么所有的公众呢? 或者相反? 还是应该有多个私人的,受保护的和公共的标签,以便操作可以与施工人员分开等等? 作出这个决定时应该考虑哪些问题?
我首先把公共接口,但我并不总是这样做。 我曾经把事情做回来,与私人,然后保护,然后公开。 回头看,这没有什么意义。
作为一个class级的开发者,你可能会熟悉它的“内脏”,但class上的用户并不在乎,至less他们不应该这样做。 他们最感兴趣的是课堂能为他们做什么,对吧?
所以我把公众放在第一位,通常由function/实用组织。 我不希望他们不得不通过我的界面来查找所有与X有关的方法,我希望他们能够有组织地看到所有的东西。
我从来没有使用多个公共/保护/私人部分 – 太混乱,不遵循我的意见。
Google赞成这个顺序 :“Typedefs和Enums,Constants,Constructors,Destructor,Methods,包括静态方法,Data成员,包括静态数据成员。
马修·威尔逊 (需要Safari订阅)推荐以下顺序:“构build,操作,属性,迭代,状态,实现,成员和我最喜欢的,不被执行”。
他们提供了很好的理由,这种方法似乎相当标准,但是无论你做什么,都要保持一致。
这是我的意见,我敢打赌,大多数人会同意,公共方法应该先走。 面向对象的一个核心原则是你不必关心实现。 只看公共方法应该告诉你所有你需要知道使用这个类。
我通常首先定义接口(被读取),这是公共的,然后保护,然后私人的东西。 现在,在许多情况下,我向前迈进了一步(如果能够处理的话)使用PIMPL模式,从真正的类的界面中完全隐藏所有的私人东西。
class Example1 { public: void publicOperation(); private: void privateOperation1_(); void privateOperation2_(); Type1 data1_; Type2 data2_; }; // example 2 header: class Example2 { class Impl; public: void publicOperation(); private: std::auto_ptr<Example2Impl> impl_; }; // example2 cpp: class Example2::Impl { public: void privateOperation1(); void privateOperation2(); private: // or public if Example2 needs access, or private + friendship: Type1 data1_; Type2 data2_; };
你可以注意到我使用下划线后缀私有(也是受保护的)成员。 PIMPL版本有一个内部的类,外界甚至没有看到这个操作。 这使得类接口完全保持清洁:只有真实的接口被暴露。 没有必要争论秩序。
由于必须build立一个dynamic分配的对象,所以在课堂build设中会有相关的成本。 对于那些并不意味着被扩展的类来说,这也是非常有效的,但是对于层次结构来说,它有一些缺点。 受保护的方法必须是外部类的一部分,所以你不能把它们推到内部类中。
像往常一样,先写人类的代码。 考虑将要使用你的课程的人,并将最重要的成员/枚举/ typedefs /无论给他们在顶部。
通常这意味着公共成员位居前列,因为这是大部分你们class的消费者最感兴趣的。受保护的是其次是私人。 通常。
有一些例外。
有时初始化顺序很重要,有时需要在公众面前公布申报。 有时候,对于一个class级来说,inheritance和延伸是更为重要的,在这种情况下,被保护的成员可以放在更高的位置。 而当黑客单元对遗留代码进行testing的时候,有时候公开的方法就更容易了 – 如果我必须犯这个错误,我会把它们放在类定义的底部。
但他们是相对罕见的情况。
我发现大多数时间“公共,受保护,私人”对于你们class的消费者来说是最有用的。 坚持不懈是一个体面的基本规则。
但这不是关于通过访问进行sorting,更多是关于通过消费者感兴趣的sorting 。
我认为这都是关于可读性的。
有些人喜欢按照固定的顺序对他们进行分组,以便每当你打开一个类声明时,你就很快知道在哪里寻找公共数据成员。
总的来说,我认为最重要的事情应该是第一位的。 对于所有类别的99.6%,粗略地说,这意味着公共方法,特别是构造方法。 然后是公共数据成员(如果有的话)(记住:封装是一个好主意),然后是任何受保护的和/或私有的方法和数据成员。
这是大型项目的编码标准可能涵盖的东西,检查可能是一个好主意。
我倾向于遵循POCO C ++编码风格指南 。
对于那些会使用你的类来首先列出公共接口的人真的很有帮助。 这是他们关心和可以使用的部分。 保护和私人可以跟随。
在公共接口中,将构造函数,属性访问器和增变器以及不同组中的运算符分组是很方便的。
请注意(取决于您的编译器和dynamic链接器),只需添加到类的末尾(即到接口的末尾),就可以保持与以前版本共享库的兼容性,而不会删除或更改其他任何内容。 (对于G ++和libtool,这是真实的,GNU / Linux共享库的三部分版本控制scheme反映了这一点。)
还有一个想法,你应该命令class级成员避免由于内存alignment而浪费的空间; 一个策略是从小到大的顺序排列。 尽pipe我从来没有用C ++或C做过。
实际上,这很less有问题。 这主要是个人喜好的问题。
首先公开的方法是非常stream行的,表面上是为了让class级的用户更容易find它们。 但是,标题永远不应该成为你的主要文档来源,所以围绕用户看你的标题的想法基础上的“最佳实践”似乎对我来说是错过了标记。
如果他们正在修改这个类,那么人们更有可能在你的头文件中,在这种情况下,他们应该关心私有接口。
无论你select什么,使你的标题干净,易于阅读。 无论我是class级的用户还是class级的维护者,能够轻松find所需要的信息是最重要的。
在我们的项目中,我们不是按照访问顺序来指定成员,而是按照使用顺序。 我的意思是,我们命令这些成员使用。 如果一个公共成员在同一个class级中使用私人成员,那么这个私人成员通常位于某个地方的公共成员的前面,如下面的(简单的)例子所示:
class Foo { private: int bar; public: int GetBar() const { return bar; } };
这里,成员栏放在成员GetBar()之前,因为前者被后者使用。 这可能会导致多个访问部分,如下例所示:
class Foo { public: typedef int bar_type; private: bar_type bar; public: bar_type GetBar() const { return bar; } };
酒吧成员使用bar_type成员,请参阅?
为什么是这样? 我不知道,看起来更自然的是,如果你在实现中遇到一个成员,你需要更多关于这个的细节(而且IntelliSense又搞砸了),你可以从你工作的地方find它。
总的来说,你的公共接口应该在任何事情之前,因为这是你的类的用户应该感兴趣的主要/唯一的东西(当然,在现实中并不总是成立,但这是一个好的开始)。
其中,成员types和常量是最好的,然后是build筑操作员,操作,然后是成员variables。
编码风格是令人惊讶的激烈对话的来源,考虑到这一点,我冒险提供不同的意见:
代码应该写成对人类来说是最易读的。 我完全同意这里几次发表的这个声明。
这个偏差是我们正在考虑的。
为了帮助课程的用户了解如何使用它,你应该编写和维护正确的文档 。 用户不应该需要阅读源代码才能使用该类。 如果这样做(手动或使用源内文档工具),那么在源中定义公共和私有类成员的顺序对于用户来说并不重要。
然而,对于需要了解代码的人来说,在代码审查,拉取请求或维护期间,订单很重要 – 规则很简单:
项目在使用之前应该被定义
这既不是一个编译器规则,也不是一个严格的公共与私人的规则,而是常识 – 人的可读性规则。 我们依次读代码,如果我们每次看到一个类成员使用,但是不知道它的types,则需要“来回转移”,这会对代码的可读性产生不利影响。
私人与公众之间严格区分违反了这一规定,因为私人class级成员在以任何公共方式使用后都会出现。
把私人领域放在第一位。
用现代的IDE,人们不会读这个类来找出它的公共接口是什么。
他们只是使用intellisence(或类浏览器)。
如果有人正在阅读类定义,通常是因为他们想知道它是如何工作的。
在这种情况下,了解领域最有帮助。 它告诉你什么是对象的部分。
完全取决于你的偏好。 没有“正确的方式”。
当我在自己的宠物项目中进行C ++时,我个人保留了在每个成员或方法声明之前放置访问修饰符的约定。