最好让所有私人成员,然后是所有受保护的成员,然后是所有公共成员?还是相反?还是应该有多个私有的,受保护的和公共的标签,以便可以将操作与构造函数分开,以此类推?做出此决定时应考虑哪些问题?
最好让所有私人成员,然后是所有受保护的成员,然后是所有公共成员?还是相反?还是应该有多个私有的,受保护的和公共的标签,以便可以将操作与构造函数分开,以此类推?做出此决定时应考虑哪些问题?
Answers:
我把公共接口放在第一位,但是我并不总是这样做。我曾经做过相反的事情,先是私有的,然后是受保护的,然后是公开的。回顾过去,这没有多大意义。
作为班级的开发人员,您可能会很熟悉班级的“内脏”,但是班级的用户并不太在乎,或者至少他们不应该这样做。他们对课程可以为他们做什么最感兴趣,对吗?
因此,我将公众放在第一位,并通常按功能/效用对其进行组织。我不希望他们必须通过我的界面来查找与X相关的所有方法,我希望他们以有组织的方式将所有这些东西放在一起。
我从不使用多个公共/受保护/私有部分-以我的观点太混乱了。
private
允许人们从隐藏的数据成员建立到类的客户能做的-逻辑上的顺序。从头开始,public
允许阅读班级的人立即看到其公共界面,并在公共部分结束后立即停止阅读,这对读者来说更容易些。
编码风格是令人惊讶的激烈对话的源泉,因此请注意,我可能会提出不同的意见:
应该编写代码,以使人类最容易阅读。我完全同意这里多次提出的这一说法。
偏差是我们要走的那一卷。
为了帮助班级用户了解如何使用它,应该编写并维护适当的文档。用户永远不需要阅读源代码即可使用该类。如果完成此操作(手动或使用源内文档工具),那么对于用户而言,在源中定义公共和私有类成员的顺序并不重要。
但是,对于需要了解的人代码的,在代码审阅,提取请求或维护期间,顺序很重要-规则很简单:
项目应在使用前定义
这既不是编译器规则,也不是严格的公共规则与私有规则,而是常识-人类可读性规则。我们按顺序读取代码,并且如果每次看到类成员都需要来回“打杂”,但是例如不知道其类型,则会对代码的可读性产生不利影响。
严格按私有与公共划分是违反此规则的,因为私有类成员将在任何公共方法中使用后出现。
与往常一样,请先为人类编写代码。考虑将要使用您的班级的人,并将最重要的成员/枚举/ typedefs /任何对他们来说放在顶部。
通常这意味着公众成员是最重要的,因为这是您班上大多数消费者最感兴趣的部分。其次是私有,然后是受保护的。通常。
有一些例外。
有时初始化顺序很重要,有时需要在公众面前声明私有。有时,继承和扩展一个类更为重要,在这种情况下,受保护的成员可能会放在更高的位置。而且,当黑客对遗留代码进行单元测试时,有时公开公共方法会更容易-如果我不得不犯下这句话,我会将其放在类定义的底部。
但是它们是相对罕见的情况。
我发现大多数时候,“公共的,受保护的,私人的”对您所在类别的消费者最有用。这是一个不错的基本规则。
但是,这与按访问顺序排序无关,而更多地是根据消费者的兴趣进行排序。
我通常首先定义(将要读取的)接口,该接口是公共的,然后是受保护的,然后是私有的。现在,在许多情况下,我会前进一步(如果可以处理的话)使用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版本具有内部类,外界甚至看不到该内部类的操作。这样可以使类接口完全干净:仅公开真实接口。无需争论秩序。
由于必须构建动态分配的对象,因此在类构造期间存在相关成本。对于那些不打算扩展的类,但在层次结构中存在一些不足的类,这也确实适用。受保护的方法必须是外部类的一部分,因此您不能真正将它们推入内部类。
我倾向于遵循POCO C ++编码样式指南。
在我们的项目中,我们不是根据访问权限而是按照使用顺序对成员进行排序。我的意思是,我们按使用顺序订购成员。如果公共成员使用同一类中的私有成员,则该私有成员通常位于公共成员前面的某个地方,如以下(简单的)示例所示:
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又被搞砸了),那么您可以在工作的上方找到它,这似乎是更自然的。
请注意(取决于您的编译器和动态链接器),您可以通过仅添加到类的末尾(即接口的末尾),而不删除或更改任何其他内容来保持与共享库以前版本的兼容性。(对于G ++和libtool来说是这样,GNU / Linux共享库的三部分版本控制方案反映了这一点。)
还有一种想法是,您应该对类的成员进行排序,以避免由于内存对齐而浪费空间。一种策略是按最小到最大的顺序订购成员。我从来没有在C ++或C中做到这一点。
首先将私有字段放在首位。
使用现代IDE,人们无需阅读该类就可以弄清楚它的公共接口是什么。
他们只是使用智能(或类浏览器)。
如果有人正在阅读类定义,那通常是因为他们想了解它的工作原理。
在这种情况下,了解这些字段最有帮助。它告诉您对象的各个部分。
vim
!但是存在一个问题:我是在编写供其他人使用的类时,我会牢记在心,即预先准备最相关的东西。那只是有礼貌,尤其是如果他们也避开了当前正在流行的IDE的话
完全取决于您的偏好。没有“正确的方法”。
在自己的宠物项目中使用C ++时,我个人遵守以下约定:我将访问修饰符放在每个成员或方法声明之前。