C/C++编程:不要试图编写独立于容器类型的代码

1060 篇文章 307 订阅

STL是以泛化原则为基础的:数组被泛化为“以其包含的对象的类型为参数”的容器。函数被泛化为“以其使用的迭代器的类型为参数”的算法,指针被泛化为“以其指向的对象的类型为参数”的迭代器。

这仅仅只是开始。容器类型被泛化为序列和关联容器,类似的容器被赋予相似的功能:

  • 标准的连续内存容器提供了随机访问迭代器,而基于节点的容器提供了双向迭代器
  • 序列容器支持push_front/push_back操作,而关联容器则不然
  • 关联容器提供了对数实践的lower_bound、upper_bound和equal_range成员函数,但是序列容器却没有提供

随着这样的泛化的不断进行,你自然也想加入到这场运动中来。这种想法是值得赞赏的。当你编写自己的容器、迭代器和算法时,你当然想这么做。可很多程序员却以一种不同的方法做泛化。它们在自己的软件中不是针对某种具体的容器,而是想把容器的概念泛化,这样它们做能使用,比如vector,而保留以后使用deque或者list的选择---但不必改变使用该容器的代码。业就是说,他们试图编写独立于容器的代码。这类泛化,尽管出发点是好的,但是几乎总是误入歧途。

即使是最热心的倡导独立于容器类型的代码的人很快就会意思到,试图编写对序列容器和关联容器都适用的代码是毫无意义的。很多成员函数仅当容器为某一类型时才存在。比如,只有序列容器才支持push_front或push_back,只有关联容器才支持count和lower_bound.....。即使是insert这样的基本操作,也会随容器类型的不同而表现出不同的原型和语义。比如,当你向序列容器插入对象时,该对象位于被插入的位置处,而对于关联容器,会按照排序规则,将该对象移动到适当的位置上......

也就是说,我们根据现实,选择合适的容器,不能写一些通用的。

有个问题,如果有一天你发现自己所选择的容器类型不是最佳的,所以你想要使用另一种容器。这时你可以使用常规的方式来是实现这种转变:使用封装技术。最简单的方式是通过对容器类型和其迭代器类型使用typedef。因此,不要这样写:

class Widget{...};
vector<Widget> vw;
Widget bestWidget;
...
vector<Widget>::iterator i = find(vw.begin(), vw.end(), bestWidget);

而要这样写:

class Widget{...};
typedef vector<Widget> WidgetContainer;                 //...
typedef WidgetContainer::iterator WCIterator;           //...

WidgetContainer cw;                                     //..
Widget bestWidget;
...
WCIterator I = find(cw.begin(), cw.end(), bestWidget);  //..

这样就使得改变容器类型要容易多了,尤其是当这种改变仅仅是增加一个自定义的分配子时,就更为方便(这一改变不影响使迭代器/指针/引用无效的规则):

class Widget{...};
template<typename T>                        //...
SpecialAllocator{...}                       // ...
typedef vector<Widget, SpecialAllocator<Widget>> WidgetContainer;      // ...
typedef WidgetContainer::iterator WCIterator;

WidgetContainer cw;
Widget bestWidget;
...
WCIterator I = find(cw.begin(), cw.end(), bestWidget);

类型定义不过是其他类型的别名,所以它带来的封装纯粹是词法上的。类型定义并不能阻止一个客户去做他们原本无法做到的事情。如果你不想把自己选择的容器暴露给客户,就得多费点劲儿。你需要使用类。

要想减少在替换容器类型时所需要修改的代码,你可以把容器隐藏到一个类中,并尽量减少那些通过类接口(而使外部)可见的、与容器相关的信息。比如,当你想创建一个顾客列表时,不要直接使用list。相反,创建一个CustomerList类,并把list因此在其中:

class CustomerList{
private:
    typedef list<Customer> CustomerContainer;
    typedef CustomerContainer::iterator CCIterator;

    CustomerContainer customers;
public:
    ...               //尽量减少那些通过该接口可见的,并且与list相关的信息
};

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值