ECE 161: Programming Languages

Fall 2005

Monday 5:00 - 6:00 Rm 643E, Wednesday 3:00 - 5:00 Rm 621E

Click here for main page of course...

Topic #10: Derived Classes, Inheritance, and Polymorphism

Derived classes allow us to represent hierarchical relations between classes. For example, triangles and circles are types of shapes, and some employees are also managers. These examples have been used used in our lectures to explain the benefits of derived classes. A class that is derived from another is declared something like this:

class Derived:public Base {
...
};

In this case, we are defining a class named "Derived" which is derived from a class named "Base". The derived class is also called a subclass, and the base class is also called a superclass (which might seem a bit confusing, since the derived class is actually a superset of the base class). The use of the keyword "public" after the ":" in the class declaration of the derived class will be discussed shortly.

A derived class is said to "inherit" properties of the base class, and this property of the language is called "inheritance". What this means is that member variables and member functions of the base class are also part of the derived class. However, not all member variables and member functions of the base class can be "seen" by the derived class. Private members of the base class can not be seen by the derived class. The reason is that if the opposite were true, any programmer could gain access to private members of a provided class (e.g., a class in a library) by simply declaring their own class to be derived from that class. However, a member variable or function can be declared to be "protected" instead of public or private, which means it appears to be private (and can not be seen) to things outside the class, but public (and thus can be seen) to derived classes.

The "public" after the ":" in the class definition of a derived class is an access specifier; the public access specifier for a derived class means that public members from the base class remain public, and protected members in the base remain protected. If protected or private is used as the access specifier, it means that this becomes the new minimum level of protection for the derived class. For example, if protected is used as the access specifier, then public members in the base become protected. If private is used, then everything becomes private, and can not be seen in classes derived from this one. It is most common to use "public" access specifiers in class definitions of derived classes.

A derived class can also be a base class. That is to say, you can define yet another class which is derived from a class that is derived from another class. Multiple classes can be derived from the same class; e.g., classes for many different shapes can all be derived from a class for shapes in general. Unlike several other languages including Java, C++ also allows a class to be derived from multiple base classes; this is called multiple inheritance. It can become quite confusing, and it is debatable whether or not it is a good thing to include this capability in the language to begin with.

If a base class includes a required constructor, then the derived class is also required to have a constructor which calls the constructor of the base class. Basically, this call sets up the part of the object that is common to the base class and derived class, and then the rest of the constructor for the derived class can set up the rest of the object. The syntax used to do this sort of thing has been explained in our lectures.

An object of a derived class is also considered an object of the base class, and can be assigned to an object declared that way. For example, if Manager is derived from Employee (since a manager is a type of employee), a Manager object can be assigned to an Employee object; only the common part of the class is copied. More importantly, a variable assigned to be a pointer to the base class can point to an object of the derived class. So, for example, a vector of pointers to Employee objects may include pointers to regular Employee objects and also pointers to Manager objects.

If one or more member functions of the base class is defined as "virtual", then "polymorphism" takes effect. Such a class is called a polymorphic type, and all classes derived from it are also polymorphic. What this means is that the compiler adds overhead to every object of the base class and all derived classes of the base; this overhead keeps track of what type of object we are dealing with. This is useful in the case that a pointer to the base class is used to access a virtual member function; the compiler adds code to the executable that looks at the overhead of the object to determine what is the actual type of the object at run-time, and it assures that the proper version of the member function will be called. That is to say, if the object is actually an object of a derived class for which the virtual member function has been redefined (overloaded), this more specific version of the member function will be called; otherwise, the member function of the base class will be called. In our lectures, we also saw the syntax for specifying that the member function of the base class should be called regardless.

A pure virtual function is a virtual function that has been made pure be defining it to be zero in the class definition. A class with one or more pure virtual functions is called an abstract class. No objects can be instantiated (declared) for such a class! All derived classes must define these functions, or they will also be abstract classes. Using abstract classes makes sense when there is a notion shared by many types of objects, but all objects will be of one of the subtypes. The common example we discussed in our lectures is that of shapes. If you are writing some sort of graphical drawing program, you may want to define a type called Shape that defines all of the things that different shapes share in common, but you may not want to allow a generic Shape object to be declared. Classes for actual shapes (circles, rectangles, triangles, etc.) must redefine any pure virtual functions for themselves, and they may also, of course, add any member variables or member functions that are specific to the shape; meanwhile, they can share the common member variables and member functions that are defined in the base.