Bjarne Stroustrup:我的经验法则是你应该有一个真正的 具有接口和隐藏表示的类当且仅当您 可以考虑类的不变量。
在当前的项目中,我有一个名为 Widget 的基类。它有x,y,宽度,高度的私有变量(基本上是一个矩形数据结构)以及每个公共getter和setter。他们对班级没有任何意义,除了是一个愚蠢的变量持有者。根据 Bjarnes 上面的评论,我摆脱了这个类,但我想知道如何与需要它们的子类共享这个数据结构。我应该单独将它们作为每个类的成员吗?将它们放在 Widget 命名空间中?
您可以使用结构体
例如
struct widget
{
int x;
int y;
int w;
int h;
};
我不确定我是否完全同意 Bjarne 的观点(除了不变量之外,更改表示的能力可能是一个重要的问题,尽管在这种情况下,甚至将实际定义移动到 PImpl 中可能很重要,而不仅仅是让它private
)。但是,如果不关心更改的成员和/或不变量,则可以将变量分组到具有对其成员public
访问权限的结构中。如果成员确实只是在没有语义意义的情况下混为一谈,您甚至可以只使用std::tuple
:
typedef std::tuple<int, int, double, double> widget;
。尽管在这种情况下,不同的成员确实具有访问函数 - 出于独立于不变量和向前兼容性的技术原因。
我认为你在那里严重误读了Stroustrup,让我强调我认为重要的部分:
我的经验法则是,你应该有一个带有接口和隐藏表示的实类,当且仅当你可以考虑该类的不变性。
我相信他不是在谈论在这种情况下不使用关键字class
,而是指的是逻辑类(或"真实类")。差异非常显着。类(注意缺少 markdown)是一个数据结构,具有自包含接口,可能是一个隐藏的实现(参见 pimpl 习语)。这意味着,(逻辑)类的工作原理对用户是不可见的,并且类对象通过成员函数和自由函数进行通信。就数据抽象而言,有时被解释为"不要从外部访问成员变量",但这只是核心思想的较浅措辞。
您仍然应该像您所做的那样(或像 Commander 或 Dietmar Kühl 建议的那样)对异构数据收集使用结构化设计。无论您是否使用class
或struct
关键字是个人喜好,但我倾向于使用struct
关键字,因此很明显,这种类型不是逻辑意义上的类,而只是一些属于一起的数据。我发现使用适当的结构比std::tuple
更可取,因为您可以命名所有成员,赋予它们意义,而不是通过索引访问它们并且必须记住每个索引应该意味着什么。此外,将来修改和扩展struct
更容易。