泛型编程:源起、实现与意义

 

泛型编程:源起、实现与意义
 
By 刘未鹏
C++ 的罗浮宫 (http://blog.csdn.net/pongba)
( 去年 12 月《程序员》的约稿 )
( 以前也写过一篇相关的文章: Generic Programming - What Are You, anyway? )
 
为什么泛型
泛型编程( Generic Programming )最初提出时的动机很简单直接:发明一种语言机制,能够帮助实现一个通用的标准容器库。所谓通用的标准容器库,就是要能够做到,比如用一个 List 类存放所有可能类型的对象 , 这样的事情;熟悉一些其它面向对象的语言的人应该知道,如 Java 里面这是通过在 List 里面存放 Object 引用来实现的。 Java 的单根继承在这里起到了关键的作用。然而单根继承对 C++ 这样的处在语言链底层的语言却是不能承受之重。此外使用单根继承来实现通用容器也会带来效率和类型安全方面的问题,两者都与 C++ 的理念不相吻合。
 
于是 C++ 另谋他法——除了单根继承之外,另一个实现通用容器的方案就是使用“参数化类型”。一个容器需要能够存放任何类型的对象,那干脆就把这个对象的类型“抽”出来,参数化它 [1]
 
template<class T> class vector {
 T* v;
 int sz;
public:
 vector(int);
 T& operator[](int);
 T& elem(int i) { return v[i]; }
 // ...
};
 
一般来说看到这个定义的时候,每个人都会想到 C 的宏。的确,模板和宏在精神上的确有相仿之处。而且的确,也有人使用 C 的宏来实现通用容器。模板是将一个定义里面的类型参数化出来,而宏也可以做到参数化类型。甚至某种意义上可以说宏是模板的超集——因为宏不仅可以参数化类型,宏实质上可以参数化一切文本,因为它本来就是一个文本替换工具。然而,跟模板相比,宏的最大的缺点就是它并不工作在 C++ 的语法解析层面,宏是由预处理器来处理的,而在预处理器的眼里没有 C++ ,只有一堆文本,因此 C++ 的类型检查根本不起作用。比如上面的定义如果用宏来实现,那么就算你传进去的 T 不是一个类型,预处理器也不会报错;只有等到文本替换完了,到 C++ 编译器工作的时候才会发现一堆莫名其妙的类型错误,但那个时候错误就已经到处都是了。往往最后会抛出一堆吓人的编译错误。更何况宏基本无法调试。
 
1
实际上,还有一种实现通用容器的办法。只不过它更糟糕:它要求任何能存放在容器内的类型都继承自一个NodeBase,NodeBase里面有pre和next指针,通过这种方式,就可以将任意类型链入一个链表内了。但这种方式的致命缺点是(1)它是侵入性的,每个能够放在该容器内的类型都必须继承自NodeBase基类。(2)它不支持基本内建类型(int、double等),因为内建类型并不,也不能继承自NodeBase。这还姑且不说它是类型不安全的,以及效率问题。
 
我们再来看一看通用算法,这是泛型的另一个动机。比如我们熟悉的 C qsort
 
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
 
这个算法有如下几个问题:
 
1.      类型安全性:使用者必须自行保证 base 指向的数组的元素类型和 compar 的两个参数的类型是一致的;使用者必须自行保证 size 必须是数组元素类型的大小。
2.      通用性: qsort 对参数数组的二进制接口有严格要求——它必须是一个内存连续的数组。如果你实现了一个巧妙的、分段连续的自定义数组,就没法使用 qsort 了。
3.      接口直观性:如果你有一个数组 char* arr = new arr[10]; 那么该数组的元素类型其实就已经“透露”了它自己的大小。然而 qsort 把数组的元素类型给“ void ”掉了( void *base ),于是丢失掉了这一信息,而只能让调用方手动提供一个 size 。为什么要把数组类型声明为 void* ?因为除此之外别无它法,声明为任意一个类型的指针都不妥(
  • 7
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值