Vector,Size_type和Encapsulation

时间:2010-02-08 14:41:55

标签: c++ stl encapsulation

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

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

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

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

      

    typedef vector :: size_type SIZE_t;

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

    另一种方法是使用size_t

    您怎么看?

6 个答案:

答案 0 :(得分:6)

我会在课堂上使用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实际上有助于封装。

答案 1 :(得分:4)

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

答案 2 :(得分:2)

那些细节会是什么? size_type暴露的唯一东西是索引所需的大小(几乎肯定是size_t)。添加typedef不会再公开任何信息。

答案 3 :(得分:1)

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

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

typedef std::size_t SIZE_T;

对我来说同样好看。

答案 4 :(得分:1)

如果你想拥有最高级别的封装,那么我会使用:

private:
    typedef std::vector<A*> container_type;
    container_type _container;
public:
    typedef container_type::const_iterator const_iterator;

    const_iterator begin()const{ return _container.begin(); }
    const_iterator end()const{ return _container.end(); }

通过使用迭代器而不是大小类型,您可以在std :: vector和std :: list之间切换。但是,如果您的班级需要随机访问,那么我会选择:

private:
    typedef std::vector<A*> container_type;
    container_type _container;
public:
    typedef container_type::size_type size_type;
    A* operator[](size_type idx)const{ return _container[idx]; }
    size_type size()const{ return _container.size(); }

如果您的类的用户不需要能够遍历内部容器的内容,那么我只是将typedef保持为私有而不提供那些公共访问器函数。

答案 5 :(得分:0)

如果您的类已在其实现中使用std::vector<A*>,则添加typedef std::vector<A*>::size_type size_type不会公开任何比已公开的详细信息。

但是,如果要进行完全封装,则需要一种技术,例如PIMPL idom或接口类(也称为协议类),完全隐藏std::vector<A*>在实现中的使用。所有:

在:

#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在源文件中定义,而不是标题,完全隐藏了实现细节中vector的选择。因此,您不再需要在头文件中#include <vector>,这有一些好处:

  • 如果不使用头文件的用户,则不必(间接)包含向量。这可以提高编译时性能,这在较大的代码库中很重要。
  • 如果您更改了实施(例如,更改为列表),则您不会冒任何(错误地)依赖#include <vector>(现在是#include <list>)的代码的风险。它发生了。