Maddyfire
Maddyfire

Reputation: 61

Why is writing general code for a common base type a bad alternative to templates in C++?

While going through a very good book on templates in C++, I came across an explanation on alternative to templates that I don't understand:

These are bad alternatives to templates in C++

  1. You can write general code for a common base type such as Object or void*.

Reason : If you write general code for a common base class you lose the benefit of type checking. In addition, classes may be required to be derived from special base classes, which makes it more difficult to maintain your code.

Can someone explain this with a code example?

Upvotes: 1

Views: 145

Answers (2)

Mike DeSimone
Mike DeSimone

Reputation: 42805

It's not the concept of a common base type that's bad. It's the use of a "Object class" that everything has to be derived from, or worse, writing code that takes void* and then, making assumptions about what the pointer points to, typecasts to a pointer to some other type and hopes for the best. This is best exemplified with containers.

The right way to implement container methods is with templates. For example:

template<typename T> void List<T>::append(const T& obj);

Object class

In the case of an Object base class, what that means is that anything you put in the container must be derived from Object, because all the container methods use Object* for the data in said container. So you get methods like this:

void List::append(Object* obj);

Two bad things here: First, that Object class has to get dragged around with your container wherever you go. Second, it's a horribly generic name and will probably conflict with an Object class from some other library.

Also, your container can never contain types that aren't Object derived directly, including primitive types like int and standard types like std::string. You'd have to "wrap" those types in Object subclasses, and then you'd have to spend time with code to extract the values from those wrapper objects, etc. It's a pain in the rear that you don't need.

void*

So you might think you could use the generic pointer void* instead:

void List::append(void* obj);

But when you do that, there are many things the container may need to do that it can't, because it has no idea what that void* points to:

  • It can't copy data objects.
  • It can't compare data objects.
  • It can't delete data objects.

and so on. (You can avoid these problems in the Object* case with virtual methods, for example declaring something like:

virtual ~Object() {}
virtual Object* clone() const;
virtual int cmp(const Object* rhs) const;

where these methods must be overridden by all subclasses, in your Object base class. But now your Object class isn't very lightweight.)

In both cases, you'd be far better off using a templated type for your container's data type. If you are worried about code bloat and have code in your container that doesn't care about the data type (because it doesn't bother with the data, such as when counting contained elements), you can put that code in a base class and have your templated container class derive from it. But most of the time nobody really cares about this "bloat" because it's much smaller than your available memory.

Type checking discarded

If you write general code for a common base class you lose the benefit of type checking.

Since you've typecast to Object* or void*, type checking went out the window for the most part. (Note: this is somewhat dated, since in some cases you can use Runtime Type Identification (RTTI) and the dynamic_cast operation to perform type checking after the fact, to make sure the object you pulled out of the container is the type you expect. But all the above-mentioned limits still apply, since the container still doesn't know what it's containing.)

Upvotes: 6

Mark Ransom
Mark Ransom

Reputation: 308206

The old qsort function used void* pointers for the start of the data and for the parameters to the comparison function. You could easily try to sort an array of double with a comparison function that compared int and wind up with a real mess.

Upvotes: 0

Related Questions