4.6 效率的权衡
效率和其他每个C++(www.cppentry.com)程序库所希望的特性往往都会互相制约。特别地,用各种可能的方法设计一个高效的程序库通常都会使程序库的实现变得更加困难,或者使程序库的使用变得更加困难。
假设我们是描述图的Graph类的设计者;我们希望Graph类能够尽可能地高效。无论给Graph类选择什么样的接口,我们都需要描述节点和边的类:
- template<class T>
- class Node {
- private:
- T t;
- //...
- };
- template<class T>
- class Edge {
- public:
- Edge(Node<T>* m, Node<T>* n);
- //...
- };
在上面的代码中,T是储存在每个节点中的值的类型。Edge类的构造函数接收两个指向要连接成这条边的节点的指针(在实际的程序库中,我们可能把Node类和Edge类嵌在类Graph里面)。
假设在每个Graph类的节点中,我们需要储存连接到此节点的边的集合;并且假设我们可以使用下面这个通用的Set类:
- template<class T>
- class Set {
- public:
- void insert(const T& t);
- bool is_empty() const;
- //...
- };
函数insert把t插入到集合中;函数is_empty当集合为空的时候返回true值。我们可以使用Set类来描述Node(节点)的入射边集合:- template<class T>
- class Node {
- private:
- Set<Edge<T>*> incedges;
- //...
- }
为了使用户可以遍历他们创建的图,我们需要提供一个函数,它可以返回各个节点入射边的集合: - template<class T>
- class Node {
- public:
- Set<Edge<T>*> incident_edges() const {
- return incedges;
- }
- //...
- };
遗憾的是,上面这个优雅的设计并不够高效。其中Set是一个通用类:从而就很难在许多特定的环境下达到最大化的效率。假设我们发现Set类对于实现Node(节点)的入射边的集合并不够高效;因此,为了令Graph类具有更高的效率,我们可以设计一个特定用途的类Incedges,用来描述节点的入射边集合: - template <class T>
- class Incedges {
- public:
- void insert(Edge<T>* e);
- bool contains(Edge<T>* e)const;
- int size() const;
- //...
- };
在上面的代码中,函数inser会往集合中加入一条边;当给定边(即参数)。属于所在集合的话,函数contain就返回true值;函数size返回集合中边的数量。
我们可以如下使用类Incedges:
- template<c1ass T>
- class Node {
- Incedges<T> incedges;
- //...
- };
如果我们正确完成了上面所有的工作,那么使用Incedges来代替Set将会给我们的程序库带来更好的实现效率。遗憾的是,这种更高效率的程序库设计将在下面两方面制约着程序库:使程序库的实现和使用更加困难。我们将在下面的小节里讨论这个问题。