C++ Concept Map

Sub- and super-types

When two classes have a sub/super-type relationship, objects of the derived class may be used where objects of the base class type are expected. This says that objects are in a is-a relationship. Thus, if a class ferrari inherits from a class sports_car, then all objects of type ferrari are also of type sports_car. Thus the following is valid:

class sports_car { ... };
class ferrari : public sports_car { ...};
void gg(sports_car);

ferrari f1;
gg(f1);

The same occurs with assignment:

sports_car s1;
ferrari f1;

s1 = f1;
is allowed because f1 is truncated to a sports_car, and then assignment can occur. However:
f1 = s1;
is not allowed because s1 cannot be converted to an object of type ferrari. An explicit cast:
s1 = (ferrai)s1;
fails in the same way.

Of course, whether this makes sense depends on the implementation of the classes, but the sub-typing principle must allow this to happen. In terms of argument passing, the (larger) object of type ferrari is truncated down to sports_car size in order to be copied into the parameter. This is safe, since the truncated part could not be used by the function anyway. The strong type-checking of C++ ensures this.

This implicit type conversion (object truncation) is called up-casting. The inverse, Down-casting, is dangerous, although possible, but only using pointers:

ferrai* pf1 = &f1;
sports_car* ps1 = &s1;
pf1 = (ferrari*)ps1;

Here an explicit cast changes the type of the pointer to s1 before the assignment, However, the extra part of the object that corresponds to the derived class is not initialized, and accessing it may be disastrous. e.g.

pf1->part_only_ferraris_have
may give an unpredictable result, since all sports car do not have such a part.


Please mail any corrections and/or suggestions to Roger Hartley at
rth@cs.nmsu.edu

Copyright © 2003 Roger Hartley