设为首页 加入收藏

TOP

4.2.2 实例化时间(3)
2013-10-07 15:02:54 来源: 作者: 【 】 浏览:67
Tags:4.2.2 实例 时间

4.2.2  实例化时间(3)

除了普通的List模板之外,如果提供了适用于指针的List版本,我们就可以减少用户需要实例化的代码数量:

  1. template<class T> 
  2. Class plist {  
  3. public:  
  4.      T* head() const;  
  5.      Plist<T> tail() const;  
  6.      Void insert (T* t);  
  7.      //...  
  8. };  

Plist描述一个值的类型为T*的链表。而且从上面代码可以看出:Plist::head的返回类型为T*类型,而不是T类型;相似地,insert函数接收一个T*类型的参数;用户现在将创建一个Plist对象,而不是以前的List对象。由下面的代码可知,Plist的实现使用了一个List对象rep,并且Plist的每个成员函数调用rep的相应的List函数:
  1. Template<class T> 
  2. Class Plist {  
  3. Public:  
  4.      T* head() const {return (T*)rep.head(); }  
  5.      Void insert(T* t) {rep.insert(t); }  
  6. Private:  
  7.      List<void*> rep;  
  8.      //...  
  9. };  

如果可以成功地把T*类型的值转化为void*类型的值,并且可以转化回来,从而得到链表节点的原始值,那么上面的代码就可以实现我们希望的功能。虽然有些T类型并没有上面的转化特性(例如,指向成员的指针类型),但普通用户所希望插入容器的类型一般都具有上述转化特性(关于Plist究竟只适用于哪些类型,应该提供清楚的文档资料)。

为了实现tail函数,我们使用了Plist的私有构造函数:

  1. template<class T> 
  2. class Plist {  
  3. private:  
  4.      Plist (const List<void*>& r) : rep(r) { }  
  5.      //...  
  6. };  
  7. template<class T> 
  8. Plist<T> Plist<T>::tail() const {  
  9.      Return Plist<T>(rep.tail());  
  10. }  

从上面可以看出,Plist成员函数的代码实体是很简单的;实际上,这些函数都是内联函数的候选函数,而且内联(我们在4.2.2节进行讨论)通常是实例化函数最快的方式;另外,我们还可以预实例化List<void*>对象。因此,比起那些使用List<Widget*>和List<Biidget*>的程序员,使用Plist<Widget>和Plist<Blidget>的程序员只需要实例化更少的代码,而且Plist的用户将看到程序创建时间也相应减少了。

指针容器虽然减少了实例化时间,但却有一个显著的缺点:容器类和指针容器,虽然从概念上讲,在C++(www.cppentry.com)的类型系统中应该是关联的,但实际上C++(www.cppentry.com)类型系统并没有实现这种关联。假设List和Plist的用户编写了下列代码:

  1. template<class T> 
  2. void insert_twice(const T& t, List<T>& 1) {  
  3.     1.insert(t);  
  4.     1.insert(t);  
  5. }  

虽然对于任何类型的List,我们都可以调用这个函数,但这个函数却不能使用Plist类型为参数。为了提供和Plist类型相同的功能,我们需要另一个函数:
  1. template<class T> 
  2. Void insert_twice(const T& t, Plist<T>& 1) {  
  3.     1.insert(t);  
  4.     1.insert(t);  
  5. }  

某些程序库设计者曾经尝试过解决这个问题,他们通过继承把一个类和这个类的指针容器相关在一起:
  1. //这种使用继承的设计并不是一种好的设计  
  2. template<class T> 
  3. class Plist : public List<void*> {  
  4. public:  
  5.      T* head() const {return (T*)Lisyt<void*>::head();}  
  6.      //...  
  7. };  

然而遗憾的是,这个设计并不是类型安全的。如考虑下面用户的代码,其中X和Y是不相关的类型:

  1. void insert_y(List<void*>& 1) {  
  2.     1.insert(new Y);  
  3. }  
  4. int main() {  
  5.      plist<X> l;  
  6.      insert_y(1);    //在List l中插入一个类型为Y*的值  
  7.      x* x = 1.head;  //出问题了,我们得到一个x*类型的值  
  8.      //...  
  9. }  

上面的代码既没有编译时错误,又没有创建时错误;然而,它把一个Y*类型的值转化为一个X*类型的值,而这并不是一个安全的转型。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇4.3.1 源文件分割 下一篇4.2.2 实例化时间(2)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: