【问题标题】:Vector, Size_type, and EncapsulationVector、Size_type 和封装
【发布时间】:2011-01-14 09:41:42
【问题描述】:

我有一个带有 vector< A*> 类型的私有数据成员的类。

该类有两个实际使用vector<A*>::size_type的公共方法:

  1. 方法返回向量中的元素数
  2. 方法按索引返回向量中的元素

我可以将以下 typedef 添加到类的公共部分:

typedef 向量::size_type SIZE_t;

但是恕我直言,它暴露了太多关于类实现的细节。

另一种方法是使用size_t

你怎么看?

【问题讨论】:

  • 我会把你的 typedef 称为“size_t”,不包括大写字母。
  • 按照惯例,甚至可能是size_type

标签: c++ stl encapsulation


【解决方案1】:

我会在课堂上使用 typedef。原因是对于std::vector,大小类型为std::size_t,但如果您稍后将代码更改为使用大小类型不是std::size_t 的容器(手卷),重新定义typedef 就足够了。

使用该 typedef 不会暴露任何实现细节,它实际上有助于封装。 typedef 中的重要元素是本地名称,而不是定义的名称。

for ( mytype::size_type i = 0; i < myelement.size(); ++i )

在上面的 for 循环中,用户代码不知道 size_type 是有符号还是无符号类型,它可以正常工作。您可以更改您的实现,并且只要您更新 typedef,前面的代码将在没有带符号/无符号比较警告的情况下编译。 typedef 实际上有助于封装。

【讨论】:

    【解决方案2】:

    对两个成员函数使用普通的旧 size_t

    【讨论】:

      【解决方案3】:

      那些细节是什么? size_type 唯一暴露的是索引所需的大小(几乎可以肯定是 size_t)。添加 typedef 不会暴露更多信息。

      【讨论】:

      • IMO,OP 认为 typedef 暴露了 vector 在幕后使用的事实。
      • 这不是封装的意义所在。用户仍然无法了解向量,或对其实现做出任何假设。但我同意你使用 size_t 代替 - 但我必须承认我自己会使用 unsigned int - 我讨厌其中带有下划线的名称:-)
      • 恕我直言,size_t 更具可读性——它在尖叫“看我代表某物的大小”(而且它是无符号的)。 ;-) YMMV
      • 我会说size_type 非常擅长尖叫它是一个尺寸。恕我直言,typedef 实际上有助于封装:用户代码不需要知道正在使用什么类型,并且 typedef 可以在不破坏用户代码的情况下更改(只要他们确实使用了 typedef 而不是具体类型)
      【解决方案4】:

      所有 size_t 类型基本上都是相同的标量类型,并且由于它是标量,因此它可以为编译器隐式转换。因此使用std::size_tstd::vector::size_type 或任何其他类似类型之间没有编译时或运行时差异。

      为班级中的尺寸类型提供typedef 是一个好主意(并遵守约定)。 IMO 您显示的 typedef 不会暴露太多您的实现,因为客户端应该使用您的 typedef,而不是直接使用 vector::size_type。但如果你喜欢

      typedef std::size_t SIZE_T;
      

      这对我来说同样不错。

      【讨论】:

      • 除了 SIZE_T 看起来像一个宏。但这只是风格问题。
      • 好吧,那是他的选择,不是我的 ;-)
      【解决方案5】:

      【讨论】:

        【解决方案6】:

        如果您的类已经在其实现中使用std::vector&lt;A*&gt;,那么添加typedef std::vector&lt;A*&gt;::size_type size_type 不会暴露比它已经暴露的更多细节。

        但是,如果您要进行完全封装,则需要使用诸如 PIMPL idom 或接口类(也称为协议类)之类的技术,完全隐藏在实现中使用了 std::vector&lt;A*&gt;

        之前:

        #include <vector>
        class A;
        class Foo {
        public:
            typedef std::vector<A*>::size_type size_type;
            size_type get_number_of_stuff() const;
        private:
            std::vector<A*> _stuff;
        };
        

        之后(使用 PIMPL 技术):

        class FooImpl;
        class Foo {
        public:
            typedef size_t size_type; // or just use size_t directly below
            size_type get_number_of_stuff() const;
        private:
            FooImpl* _impl;
        };
        

        FooImpl 是在你的源文件中定义的,而不是在头文件中,在实现细节中完全隐藏了向量的选择。因此,您不再需要在头文件中使用#include &lt;vector&gt;,这有几个好处:

        • 如果你的头文件的用户不使用它,他们不必(间接地)包含向量。这可以提高编译时性能,这在大型代码库中很重要。
        • 如果您更改实现(例如,列出),您不会冒险破坏任何(错误地)依赖于您的 #include &lt;vector&gt;(现在为 #include &lt;list&gt;)的代码。它发生了。

        【讨论】:

        猜你喜欢
        • 2021-01-26
        • 1970-01-01
        • 2020-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-05
        • 2017-12-23
        • 1970-01-01
        相关资源
        最近更新 更多