直接访问成员或始终使用getter

时间:2010-09-27 08:35:31

标签: c++ coding-style

注意:C ++特定问题

当一个类使用getter访问自己的成员数据时,我个人觉得它很奇怪/丑陋。我知道性能影响是没有但我只是不喜欢看到所有这些方法调用。 是否有任何强有力的论据,或者它只是个人偏好中的一个,应留给每个编码人员,还是在编码标准中任意控制?

更新:我的意思是简单的getter,特别是对于'非公开类的成员。

11 个答案:

答案 0 :(得分:12)

愿意在班级成员实施中使用getter / setter是我的金丝雀,告诉你的班级正在不合理地增长。它告诉你的班级正在尝试做太多不同的事情,它有几个目的,它应该提供一个

实际上,当您使用类的一部分来存储或访问数据时,通常会遇到这种情况,而另一部分则用于对其进行操作。也许你应该考虑使用一个独立的类来存储和访问你的数据,另一个用来提供更高的视图,对你的数据进行更复杂的操作。

答案 1 :(得分:11)

您可能想要使用getter / setter的原因是因为它隐藏了实现。如果您使用getter / setter以防实现确实发生变化,则不必重写所有代码,因为这些成员可以继续工作。

编辑基于许多聪明的评论:

对于使用setter和getters本身的类,这可能取决于细节。毕竟,类本身可以使用特定类的实现。在通常实例化类的情况下,类应该直接将成员值用于其自己的成员(私有或其他)及其父类(如果它们受到保护),并且仅在这些成员使用时使用getter / setter。私有父类。

在抽象类型的情况下,它通常根本不包含任何实现,它应该提供纯虚拟的getter和setter,并且只使用它实现的方法中的那些。

答案 2 :(得分:7)

显而易见

受保护成员的getter和setter与public一样有意义......派生类只是客户端代码的另一种形式,从它们封装实现细节仍然很有用。我并不是说总是这样做,只是为了按照正常的方式来衡量利弊。

然而,私人会员的吸气剂和制定者很少是净利益:

  • 它确实提供了相同类型的封装优势

    • 断点的单个位置/在开发期间记录get / set +不变检查(如果一致使用)
    • 虚拟潜力
    • 等...

    但仅限于可能相对较小的相同结构/类的实现。在企业环境中,对于公共/受保护的成员数据,这些好处可以足以证明获取/设置方法的合理性:日志记录功能最终可能依赖于数百万行代码,以及数百或数千个库和应用程序对标头的更改可能会触发重新编译。一般来说,单个类的实现不应该超过几百(或最差千)行 - 不足以证明封装内部私有数据的大小或复杂性......可以说它构成了“代码味道”。

不可见的

  • 获取/设置方法偶尔比直接变量访问更具可读性(尽管通常更不易读)
  • get / set方法可以为代码生成的成员或朋友方法(无论是来自宏还是外部工具/脚本)提供更加统一和方便的界面。
  • 如果成为可能的话,在成为会员或朋友之间转换为独立帮助功能所需的工作量减少
  • 对于通常只是该类用户的人(因为更多操作通过公共接口或以公共界面的方式表达),可以使实现更容易理解(并因此可维护)

这个问题有点超出范围,但值得注意的是,类通常应提供面向操作的命令,事件触发的回调等,而不是鼓励获取/设置使用模式。

答案 3 :(得分:4)

似乎大多数人没有正确地阅读你的问题,问题是关于访问其自己的班级成员类方法是否应该使用getter和setter;不是关于访问班级成员的外部实体。

我不打算使用getter和setter访问类自己的成员。

但是,我也保持我的课程很小(通常约200-500行),这样如果我确实需要更改字段或更改其实现或如何计算它们,搜索和替换不会太多工作(事实上​​,我经常在早期开发期间更改变量/类/函数名称,我是挑剔的名字选择器。)

当我期望在不久的将来改变实现时,我只使用getter和setter来访问我自己的类成员(例如,如果我正在编写一个可以快速编写的次优代码,但计划在未来)可能涉及从根本上改变所使用的数据结构。相反,在我已经有计划之前,我不使用getter和setter;特别是,我不会使用getter和setter来期待改变我不太可能永远不会改变的东西。

对于外部接口,我严格遵守公共接口;所有变量都是私有的,除了运算符重载之外,我避免使用friend;我保守地使用protected成员,他们被认为是一个公共接口。但是,即使对于公共接口,我通常仍然避免使用直接的getter和setter方法,因为它们通常表示OO设计不良(任何语言的每个OO程序员都应该阅读:Why getter and setter methods are Evil)。相反,我有一些方法可以做一些有用的事情,而不仅仅是获取值。例如:

class Rectangle {
    private:
        int x, y, width, height;
    public:
        // avoid getX, setX, getY, setY, getWidth, setWidth, getHeight, setHeight
        void move(int new_x, int new_y);
        void resize(int new_width, int new_height);
        int area();
}

答案 4 :(得分:3)

唯一的优点是它允许在不改变外部界面的情况下更改内部表示,允许延迟评估,或者为什么不访问计数。

根据我的经验,我这样做的次数非常非常低。而且你似乎也这样做了,我也更愿意避免吸气剂/安装者的丑陋和沉重。如果我真的需要它,那么之后改变它并不困难。

当你在自己的实现函数中使用自己的getter / setter来讨论一个类时,你应该考虑在可能的情况下编写非朋友的非成员函数。它们改进了封装,如here所述。

答案 5 :(得分:2)

支持使用getter的论据是,您可能决定有一天更改成员字段的计算方式。例如,您可能决定需要它与其他成员合格。如果你使用了一个getter,你所要做的就是改变一个getter函数。如果不这样做,则必须更改当前和将来使用该字段的每个位置。

答案 6 :(得分:2)

只是一个粗略的例子。这有帮助吗?

struct myclass{
    int buf[10];
    int getAt(int i){
        if(i >= 0 && i < sizeof(buf)){
            return buf[i];
        }
    }

    void g(){
        int index = 0;
        // some logic
        // Is it worth repeating the check here (what getAt does) to ensure
              // index is within limits
        int val = buf[index];
    }
};

    int main(){}

编辑:

我会说这取决于。如果getter进行某种验证,最好通过验证,即使它意味着类成员正在进行验证。通过公共入口点的另一种情况可能是有用的是当访问需要基本上以顺序和同步的方式时,例如,在多线程场景中。

答案 7 :(得分:2)

这实际上是通过抽象get(getter)的方式来支持类的面向对象。并且只是提供更容易的访问。

答案 8 :(得分:1)

通过使用get / set函数包装其访问权来保护成员变量有其优点。有一天你可能希望让你的类线程安全 - 在那种情况下,你会感谢你使用那些get / set函数

答案 9 :(得分:1)

简单的回答。如果你正在写一个单一的拍摄程序,那将永远不会改变,你可以保持安静,不做任何事情。

但是,如果您编写的程序可能会随着时间的推移而改变或被编写,或者其他人可能会使用该代码,请使用getter。

如果您使用getter,它有助于以后更快地更改代码,例如在属性上设置保护以验证值的正确性,或计算对属性的访问(调试)。

Getters对我来说很简单(免费午餐)。编写代码的程序员不需要getter,他想要它们。

希望有所帮助。

答案 10 :(得分:0)

我的想法如下。

所有内容(如果可能)都应该是静态的,常量的和私有的。

  • 因为您需要实例化一个变量,这意味着多个唯一的变量 复制您删除静态。

  • 由于需要一个可修改的变量,因此删除了const。

  • 由于您需要一个类/变量以供其他类访问,因此将其删除 私人的。

“二传手”的用法-通用。

  • 如果该值只能由班级更改,并且 我们要保护它。这样我们可以检索到的当前状态 此值不会改变它的值。
  • 如果您打算提供塞特犬,则不应该使用塞特犬 用它。此时,您只需将值转换为public 并直接对其进行修改。因为这是获取/设置的目的。

  • 如果您打算做更多的事情,那么简单地使用二传手就毫无用处了 “ this.value = value”。那你不应该叫它“ SetValue” 而不是描述它的实际作用。

  • 如果假设您要在修改值之前 “获取”是很有价值的。然后不要将其称为“ GetValue”。这是模棱两可的 您的意图,尽管您可能知道发生了什么。有人 除非他们查看了该函数的源代码,否则其他人不会。

  • 如果说您确实只是在获取/设置一个值,但是 做某种形式的安全。即大小检查,空检查等。 是另一种方案。但是,您仍然应该在 名称,例如“ SafeSetValue”,“ SafeGetValue”或类似“ printf”中的 有“ printf_s”。

获取/设置情况的替代方式

  • 我个人有一个例子。您可以看到我如何处理 获取/设置方案。我有一个GameTime类可以存储各种各样的内容吗 值和每个游戏滴答声,这些值都会更改。

    https://github.com/JeremyDX/DX_B/blob/master/DX_B/GameTime.cpp

  • 如上所示,我的“ GETS”实际上不是
    的“ GETS” 值,除非在不需要修改的小情况下。而是 它们是我试图从中检索的值的描述
    GameTime类。每个值都是“静态专用”。我不能做const
    给定信息,直到运行时才获取,而我将其保留 静态的,因为没有目的要有多个Timing实例。

  • 您还将看到,我对任何这些数据都没有执行“ SET”的方法,但是有两个函数“ Begin()”和“ Tick()”都改变了价值观。这就是应该处理所有“设定者”的方式。基本上,“ Begin()”函数会重置所有数据并加载我们不能将其设置为常量的常量,因为这是我们在运行时检索到的数据。然后TICK()在这种情况下会随着时间的流逝更新特定的值,因此我们可以获得最新的信息。

  • 如果深入研究代码,您会发现值“ ResetWindowFrameTime()”和“ ElapsedFrameTicks()”。通常,我不会做这样的事情,而只是将值设置为public。如您所见,因为我正在检索值并设置值。这是Set / Get的另一种形式,但它仍然使用适合场景的命名,并且使用来自私有变量的数据,因此提取另一个私有变量然后乘以该变量并不有意义,而是在此处进行工作并提取结果。除将其重置为当前帧索引然后检索经过的帧外,也无需编辑该值。当我在屏幕上打开一个新窗口时使用它,这样我可以知道我已经浏览该窗口多长时间了,并据此进行操作。