2010-02-08 67 views
4

我有一个类vector< A*>类型的私人数据成员。Vector,Size_type和Encapsulation

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

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

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

typedef ve ctor :: size_type SIZE_t;

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

另一种方法是使用size_t

您认为如何?

+0

我会打电话给你的typedef“size_t”,没有大写字母。 – Manuel 2010-02-08 15:01:21

+5

根据惯例,甚至可能是'size_type'。 – UncleBens 2010-02-08 16:11:38

回答

4

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

2

这些是哪些细节? size_type唯一公开的是索引所需的大小(几乎可以肯定是size_t)。添加typedef不会公开任何更多信息。

+0

IMO,OP认为typedef暴露了在引擎盖下使用'vector'的事实。 – dirkgently 2010-02-08 14:46:44

+0

虽然这不是封装问题。用户仍然无法了解矢量,或对其实现做出任何假设。但我同意你有关使用size_t来代替 - 但我必须承认我会使用unsigned int自己 - 我讨厌带有下划线的名字:-) – 2010-02-08 14:49:48

+0

恕我直言,'size_t'更具可读性 - 它尖叫出来“看我代表大小的东西“(并且它是无符号的)。 ;-) YMMV – dirkgently 2010-02-08 14:52:57

1

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

这是一个好主意(并遵守惯例)为您的班级中的大小类型提供typedef。 IMO显示的typedef没有公开太多的实现,因为客户端应该使用typedef,而不是直接使用vector::size_type。但如果你更喜欢

typedef std::size_t SIZE_T; 

看起来同样很好,我。

+2

除了SIZE_T外观像一个宏。但那只是一个风格问题。 – 2010-02-08 15:20:22

+0

那么,这是他的选择不是我的;-) – 2010-02-08 17:59:26

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

如果你想有封装的最大水平,那么我会用:

 
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之间切换: :列表。但是,如果随机访问是为你的类的要求,然后我会去:

 
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(); } 

如果你的类的用户并不需要能够通过内部容器的内容重复,那么我会只需将typedefs保持为私有,而不提供这些公共访问器函数。

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

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

但与PIMPL你不使用std :: vector :: size_type更多,但使用size_t来代替。如果我仍然想使用容器的大小(std :: vector :: size_type),那么它会将矢量/列表带入用户代码。 – dimba 2010-02-08 20:40:05

+0

@idimba:STL容器通常将size_t用于size_type,因此使用size_t是一种安全的选择。它也适用于32位vs.64位(与使用int,unsigned int等相反)但是,如果你仍然想使用'std :: vector :: size_type'作为基础,那么你至少必须'#include '和forward声明'类A',即使你使用typedef来帮助隐藏它。 – 2010-02-08 22:29:43