繁体   English   中英

Vector,Size_type和Encapsulation

[英]Vector, Size_type, and Encapsulation

我有一个类,其中包含vector< A*>类型的私有数据成员。

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

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

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

typedef vector :: size_type SIZE_t;

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

另一种方法是使用size_t

你怎么看?

我会在类中使用typedef。 原因是对于std::vector ,size类型是std::size_t ,但是如果稍后更改代码以使用容器(手动滚动),其大小类型不是std::size_t重新定义typedef就足够了。

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

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

在上面的for循环中,用户代码不知道size_type是有符号类型还是无符号类型,它只是起作用。 您可以更改您的实现,只要您更新typedef,之前的代码将编译而没有签名/未签名的比较警告。 typedef实际上有助于封装。

对两个成员函数使用plain old size_t

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

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

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

typedef std::size_t SIZE_T;

对我来说同样好看。

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

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保持为私有而不提供那些公共访问器函数。

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

但是,如果要进行完全封装,则需要一种技术,如PIMPL idom或接口类(也称为协议类),完全隐藏std::vector<A*> <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> 它发生了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM