【问题标题】:Classes and Member Variables类和成员变量
【发布时间】:2011-06-05 08:16:42
【问题描述】:

假设我有一个名为myList 的容器类。此容器类有一个名为 capacity 的私有成员变量,它保存实例中值的数量。

类的用户访问capacity 可能是有益的,例如,在循环遍历每个值时知道他们何时到达终点。因此,capacity 应该是公开的。

但是,这也将允许该类的用户修改 capacity,这显然会搞砸。

myList myInstance;
myInstance.capacity = 123;

拥有一个只返回capacity 的值的公共成员函数是否会被视为不好的做法,这将是一个私有变量?例如:

unsigned int getCapacity()
{
    return capacity;
}

每当capacity 的值发生变化时,如果“克隆”变量更新为capacity 的值会怎样?该类的用户将访问公共“克隆”而不是私有变量本身。

【问题讨论】:

  • “对于班级的用户来说,访问容量可能是有益的……”——我怀疑这是否真的。使用std::vector 证明暴露容量是没有用的。另一方面,getter(和setter)破坏了封装,它们几乎和公共变量一样糟糕,所以在创建它们时必须有一个很好的借口。

标签: c++ class visibility private-members


【解决方案1】:

有一个容量吸气剂。
但将其标记为 const 成员:

unsigned int getCapacity()  const
{                        //^^^^^^^ 
    return capacity;
}

第二种解决方案不起作用。
因为它不可靠(一个用户可能会更新它,然后下一个用户在读取它时会得到一个无效的值)。

尽管您应该考虑您班级的用户是否真的需要这些信息。
他们可以用它做什么?

所以如果容量不够,你要预先分配内存吗?

MyList   x;
// I am going to add 10 items make sure there is enough room.
if (x.size() + 10 < x.capacity())
{    x.resize(x.size() + 10);
}

在这种情况下,总是重新调整大小。然后让你的容器在它已经有空间的情况下什么都不做。

x.resize(x.size() + 10);  // If the container has enough space do nothing. 
                          // Otherwise make sure there is enough room for 10 more items.

通常最好让一个对象管理它自己,而不是提供对其内部状态的访问以允许其他对象间接管理它。即使您将实现与实际变量解耦,您仍然将自己与具有容量的接口耦合,它并没有真正为您提供有意义的好处。

所以方法应该(通常)是对对象执行动作的动作(动词)。这些动作操纵对象的状态。让动作成为您的对象的接口。请注意,一旦您为对象定义了接口,就很难更改该接口(删除功能)。

【讨论】:

  • @Maxpm:它通知编译器该方法不会改变对象的状态。 const 正确性是 C++ 的重要组成部分,它允许编译器通过验证不改变状态的方法不会意外调用改变状态的方法来阻止你做傻事。
【解决方案2】:

访问器是一个很好的解决方案。这是 STL 选择的。见 std::vector::capacity(), std::vector::size(), ...

【讨论】:

    【解决方案3】:

    您描述的第一个解决方案称为 getter,拥有这些被认为是一种好习惯。

    第二个解决方案实际上并不是一个解决方案,它只是添加了第二个变量并引入了更新它的必要性。

    【讨论】:

      【解决方案4】:

      不,这不是一个坏习惯。事实上,使用 getter 和 setter 被认为是一种最佳实践。

      【讨论】:

        【解决方案5】:

        这根本不是一个坏习惯,实际上你需要这样做。

        【讨论】:

          【解决方案6】:

          如果您有一个公共 getter,您可以只返回容量的副本或 const 引用。

          这将允许客户查看但不能修改数据。

          【讨论】:

          • 公开实现细节通常不是一个好主意。
          • @John Dibling - 你指的是什么“实施细节”?
          • capacity 成员变量的类型。如果您返回一个 const 引用,则表明这是一个 unsigned 或任何它可能是的。如果将来发生这种变化(比如unsigned long),所有客户端代码都必须重新编译。而是按值返回值不会公开实现细节。
          • @John Dibling - 除非我弄错了,如果您按价值返回并增加容量大小,对于现有客户来说仍然是一个二元中断,所以我看不出您的评论的相关性。
          • 这就是抽象类发挥作用的地方。是学历的问题。您可以通过使用抽象类和工厂函数将接口与实现完全分离,但这需要库开发人员做更多的工作。您可以完全忽略接口与实现的分离,但这意味着库用户需要更多的工作或更长时间/更频繁的编译。或者你可以采取中间方法,在两者之间取得平衡。针对不同场景的三种方法,因为没有一种方法适用于所有情况。
          【解决方案7】:

          只要您通过值或 const 指针返回 private 成员,而不是通过非常量指针返回其地址,就可以了。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-06-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-08-15
            相关资源
            最近更新 更多