The Standard Containers as Class Templates

发表于:2007-07-01来源:作者:点击数: 标签:
The Standard Containers as Class Templates by , from the Book MAR 22, 2002 Why do generic classes make excellent containers? This excerpt from C++ by Example (Que, 2001) by Steve Donovan shows some of the consequences of not having them. T

The Standard Containers as Class Templates
by , from the Book
MAR 22, 2002

Why do generic classes make excellent containers? This excerpt from C++ by Example (Que, 2001) by Steve Donovan shows some of the consequences of not having them.

This article is provided courtesy of .

This article is excerpted from C++ by Example (Que, 2001, ISBN: 0789726769), by Steve Donovan.

 

How were things handled before templates were available? The first problem with creating containers without templates is that they are not type safe. Imagine if you had only list<void *>; any pointer could be put in such a list. You would need to write code like this:

typedef list<void *> List; // the one & only list... void draw_shapes(TG& tg, const List& ls) { List::iterator li; for(li = ls.begin(); li != ls.end(); ++li) static_cast<Shape *>(*li)->draw(tg); }

This looks nasty, and it is nasty. There is no guarantee at runtime that this list contains only pointers to Shape. A program would inevitably decide to put something odd in the list when it was being used for some crucial operation on the other side of the planet (or, indeed, another planet altogether). It is not possible to check all the possibilities in even a moderate-sized application. Type safety is a guarantee that no surprises with odd types can happen—that they will be caught by the compiler, not the customer.

Traditional object-oriented languages rely on runtime-type information. Every class derives from some polymorphic base class, usually called Object. In Delphi, for instance, deriving from Object is implicit, so the is operator can always work. Of course, this strategy works in C++ as well, as long as the ultimate base class Object has at least one virtual method. The class Shape will have to be derived from Object in some way. Then dynamic_cast() will work. The previous example becomes this:

typedef list<Object *> List; // the one & only list... void draw_shapes(TG& tg, const List& ls) { List::iterator li; for(li = ls.begin(); li != ls.end(); ++li) { Shape *ps = dynamic_cast<Shape *>(*li) if (ps != NULL) ps->draw(tg); } }

There is now a proper runtime guarantee, at the cost of continuous checking. But what should you do if the object isn´t a Shape pointer? Surely you should raise an alarm or make a note somewhere. Although this code is safe, it could be masking an error somewhere else. There should only be Shape pointers in this list; it isn´t considered particularly clever to keep different kinds of objects together.

NOTE

Java tends to do things like this. Because there are no parameterized types; typically, code needs plenty of typecasts, which are all dynamic.

原文转自:http://www.ltesting.net