2013-03-28 22 views
4

我知道在您的班级中设置公共字段被认为是一个坏主意。但是当你的课程包含许多分层数据结构和领域时,最好的方法是什么?例如:安装程序/获取程序和分层数据结构

class A {B d1; C d2; D d3;} 
class B {E d4; F d5;} 
class E {G d6; int d7;} 

在C中,访问这样的数据结构是很容易的,例如, ptr_to_A-> d1.d4.d7等等......但是当我们使用setter/getters时,该怎么办?当在C++中使用setter和getter时,像A.get_d1()。get_d4()。get_d7()这样的表达式似乎并不方便,并且它们强制返回引用。由于一些结构相当大,所以按价值回报似乎是一个可怕的想法。

您在这些情况下使用哪种方法或编码风格?也许摆脱setter/getters和公开这些领域?

回答

2

我知道在班上有公共领域被认为是一个坏主意。

这是一个来自过去十年Java开发的声明。你应该考虑一个成员应该是公开还是私人的成员一个成员。有时候公共数据成员是正确的想法。考虑以下问题:

  1. 我是否需要对此成员保持不变?
  2. 这个成员可以有一个无效值吗?
  3. 我是否希望界面给出此成员的替代表示形式?

如果上述任何问题的答案是肯定的,那么您可能需要使用getter。

还要考虑是否真的有意义,单独设置成员。也许你应该用构造函数设置成员,并且你想提供一些其他的接口来修改这些成员。

当在C++中使用getter和setter方法,这样的表达式A.get_d1()。get_d4()。get_d7()看起来很方便

不虽然这不是太不凡有相当深的嵌套的数据结构,通常一段特定的代码不应该深入研究它。如果确实如此,我想它可能做得比应该做得更多,超越了它的单一责任。但是,如果它是一个共同的任务,从A对象获取d7,也许A应该将其暴露在它的接口:

int A::get_d7 { 
    return get_d1().get_d4().get_d7(); 
} 

由于一些结构是相当大的,由价值回归似乎是一个可怕的想法。

实际上,用现代C++,这根本不是问题。按值传递应该被认为是对象传递的默认模式。这是因为临时对象现在可以从中移出,这实质上是一种非常有效的复制形式。

+0

但是,当按值返回时,它肯定会创建一个数据结构的副本。如果其中一个嵌套数据结构很大,考虑到我只想读取一个字段,这不是一个好主意。 – jbgs

+0

@jbgs这取决于它返回的内容。如果它返回一个成员对象,是的,它将不得不复制它。 –

+0

是的,这些嵌套的数据结构是成员对象。实际上我认为常见的C++编码风格并不适合我正在开发的这种应用(微电子仿真)。 – jbgs

1

如果你只是使用类作为一个纯粹的数据结构,并有与要封装的数据没有行为,然后用struct,而不是直接访问的字段。 Bjarne Stroustrup recommends this approach。这相当于使用class并声明所有成员为public,但将其称为struct反而更清楚地表明它只不过是简单的数据收集。

如果您不仅仅是存储数据,而是使用getters和setter。

当在C++中使用getter和setter方法,这样的表达式 A.get_d1()。get_d4()。get_d7()似乎并不方便,而且他们强迫 返回引用。由于一些结构相当大,按价值返回 似乎是一个可怕的想法。

不,您可以选择是通过引用还是按值返回。

+0

大多数类也包括一些成员函数。 – jbgs

2

在我的编码风格中,类不应公开“原始”数据成员,而只能是getter和setter(即使它们是简单的单行方法)。

这是因为未来可以升级代码,单线方法可以扩展到更复杂的东西(或者可以添加一些仅用于调试的构建功能来检查某些不变量等),所以最好让客户端的接口保持一致(如果你暴露“原始”数据成员,这是不可能的)。

您可以避免使用前缀get_(),只需将该数据成员视为一个简单的(不含get_...)名称的“属性”即可。

class Shape 
{ 
public: 
    .... 

    COLORREF Color() const // Just Color() i.e. the property name, without get_... 
    { 
    return m_color; 
    } 

private: 
    COLORREF m_color; 
}; 

并编写客户端代码,如:

Shape s; 
COLORREF someColor = s.Color(); 

这看起来好像没什么问题。

对于您可以像使用语法二传手:

Shape& Color(COLORREF color) 
{ 
    m_color = color; 
    return *this; 
} 

,并写出这样的客户端代码:

Shape s; 
s.Color(...).Draw(); // set color and draw shape 

如果属性的类型是东西比COLORREF更复杂(这是一个32位的DWORD),你可以使用一个模式,如:

std::wstring Name() const // getter 
{ 
    return m_name; 
} 

Shape& Name(std::wstring name) // setter 
{ 
    // Pass by value and move from the value (C++11 move semantics) 
    m_name = std::move(name); 

    return *this; 
}