Inheriting a Class - Inheritance - C++ For Dummies (2014)

C++ For Dummies (2014)

Part IV



image Visit for great Dummies content online.

In this part…

· Inheriting a base class

· Exploring relationships

· Factoring common properties

· Declaring abstract classes

· Visit for great Dummies content online

Chapter 19

Inheriting a Class

In This Chapter

arrow Defining inheritance

arrow Inheriting a base class

arrow Constructing the base class

arrow Exploring meaningful relationships: The IS_A versus the HAS_A relationship

This chapter discusses inheritance, the ability of one class to inherit capabilities or properties from another class.

Inheritance is a common concept. I am a human (except when I first wake up in the morning). I inherit certain properties from the class Human, such as my ability to converse (more or less) intelligently and my dependence on air, water, and carbohydrate-based nourishment (a little too dependent on the latter, I’m afraid). These properties are not unique to humans. The class Human inherits the dependencies on air, water, and nourishment from the class Mammal, which inherited it from the class Animal.

The capability of passing down properties is a powerful one. It enables you to describe things in an economical way. For example, if my son asks, “What’s a duck?” I can say, “It’s a bird that goes quack.” Despite what you may think, that answer conveys a considerable amount of information. He knows what a bird is, and now he knows all those same things about a duck plus the duck’s additional property of “quackness.” (Refer to Chapter 11 for a further discussion of this and other profound observations.)

Object-oriented (OO) languages express this inheritance relationship by allowing one class to inherit from another. OO languages can generate a model that’s closer to the real world (remember that real-world stuff!) than the model generated by languages that don’t support inheritance.

C++ allows one class to inherit another class as follows:

class Student

class GraduateStudent : public Student

Here, a GraduateStudent inherits all the members of Student. Thus, a GraduateStudent IS_A Student. (The capitalization of IS_A stresses the importance of this relationship.) Of course, GraduateStudent may also contain other members that are unique to a GraduateStudent.

Do I Need My Inheritance?

Inheritance was introduced into C++ for several reasons. Of course, the major reason is the capability of expressing the inheritance relationship. (I’ll return to that in a moment.) A minor reason is to reduce the amount of typing. Suppose that you have a class Student, and you’re asked to add a new class called GraduateStudent. Inheritance can drastically reduce the number of things you have to put in the class. All you really need in the class GraduateStudent are things that describe the differences between students and graduate students.

This IS_A-mazing

To make sense of our surroundings, humans build extensive taxonomies. Fido is a special case of dog, which is a special case of canine, which is a special case of mammal, and so it goes. This shapes our understanding of the world.

To use another example, a student is a (special type of) person. Having said this, I already know a lot of things about students (American students, anyway). I know they have social security numbers, they watch too much TV, and they daydream about the opposite sex (the male ones, anyway). I know all these things because these are properties of all people.

In C++, we say that the class Student inherits from the class Person. Also, we say that Person is a base class of Student, and Student is a subclass of Person. One final phrase and then I'll stop: Student extends the class Person. Finally, we say that a Student IS_A Person (using all caps is a common way of expressing this unique relationship — I didn’t make it up). C++ shares this terminology with other object-oriented languages.

Notice that although Student IS_A Person, the reverse is not true. A Person IS not a Student. (A statement like this always refers to the general case. It could be that a particular Person is, in fact, a Student.) A lot of people who are members of class Person are not members of class Student. In addition, class Student has properties it does not share with class Person. For example, Student has a grade point average, but Person does not.

The inheritance property is transitive. For example, if I define a new class GraduateStudent as a subclass of Student, GraduateStudent must also be Person. It has to be that way: If a GraduateStudent IS_A Student and a Student IS_A Person, a GraduateStudent IS_A Person.

Another minor side effect has to do with software modification. Suppose you inherit from some existing class. Later, you find that the base class doesn't do exactly what the subclass needs. Or perhaps the class has a bug. Modifying the base class might break other code that uses that base class. Creating and using a new subclass that overloads the incorrect feature with a corrected version solves your problem without causing someone else further problems.

How Does a Class Inherit?

Here’s the GraduateStudent example filled out into a program InheritanceExample:

// InheritanceExample - demonstrate an inheritance
// relationship in which the subclass
// constructor passes argument information
// to the constructor in the base class
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
class Advisor {}; // define an empty class

class Student
Student(const char *pName = "no name")
: name(pName), average(0.0), semesterHours(0)
cout << "Constructing student " << name << endl;

void addCourse(int hours, float grade)
cout << "Adding grade to " << name << endl;
average = semesterHours * average + grade;
semesterHours += hours;
average = average / semesterHours;

int hours() { return semesterHours;}
float gpa() { return average;}

string name;
double average;
int semesterHours;

class GraduateStudent : public Student
GraduateStudent(const char *pName, Advisor adv,
double qG = 0.0)
: Student(pName), advisor(adv), qualifierGrade(qG)
cout << "Constructing graduate student "
<< pName << endl;

double qualifier() { return qualifierGrade; }

Advisor advisor;
double qualifierGrade;

int main(int nNumberofArgs, char* pszArgs[])
// create a dummy advisor to give to GraduateStudent
Advisor adv;

// create two Student types
Student llu("Cy N Sense");
GraduateStudent gs("Matt Madox", adv, 1.5);

// now add a grade to their grade point average
llu.addCourse(3, 2.5);
gs.addCourse(3, 3.0);

// display the graduate student's qualifier grade
cout << "Matt's qualifier grade = "
<< gs.qualifier() << endl;

// wait until user is ready before terminating program
// to allow the user to see the program results
cout << "Press Enter to continue..." << endl;
cin.ignore(10, '\n');
return 0;

This program demonstrates the creation and use of two objects, one of class Student and a second of GraduateStudent. The output of this program is as follows:

Constructing student Cy N Sense
Constructing student Matt Madox
Constructing graduate student Matt Madox
Adding grade to Cy N Sense
Adding grade to Matt Madox
Matt's qualifier grade = 1.5
Press Enter to continue...

Using a subclass

The class Student has been defined in the conventional fashion. The class GraduateStudent is a bit different, however. The colon followed by the phrase public Student at the beginning of the class definition declares GraduateStudent to be a subclass of Student.

image The appearance of the keyword public implies that there is probably protected inheritance as well. All right, it’s true, but protected inheritance is rarely used and beyond the scope of this book.

Programmers love inventing new terms or giving new meaning to existing terms. Heck, programmers even invent new terms and then give them a second meaning. Here is a set of equivalent expressions that describes the same relationship:

· GraduateStudent is a subclass of Student.

· Student is the base class or is the parent class of GraduateStudent.

· GraduateStudent inherits or is derived from Student.

· GraduateStudent extends Student.

As a subclass of Student, GraduateStudent inherits all its members. For example, a GraduateStudent has a name even though that member is declared up in the base class. However, a subclass can add its own members, for example qualifierGrade. After all, gs quite literally IS_A Studentplus a little bit more.

The main() function declares two objects, llu of type Student and gs of type GraduateStudent. It then proceeds to access the addCourse() member function for both types of students. main() then accesses the qualifier() function that is only a member of the subclass.

Constructing a subclass

Even though a subclass has access to the protected members of the base class and could initialize them, each subclass is responsible for initializing itself.

Before control passes beyond the open brace of the constructor for GraduateStudent, control passes to the proper constructor of Student. If Student were based on another class, such as Person, the constructor for that class would be invoked before the Student constructor got control. Like a skyscraper, the object is constructed starting at the “base”-ment class and working its way up the class structure one story at a time.

Just as with member objects, you often need to be able to pass arguments to the base class constructor. The example program declares the subclass constructor as follows:

GraduateStudent(const char *pName, Advisor adv,
double qG = 0.0)
: Student(pName), advisor(adv), qualifierGrade(qG)
// whatever else the constructor does

Here the constructor for GraduateStudent invokes the Student constructor, passing it the argument pName. C++ then initializes the members advisor and qualifierGrade before executing the statements within the constructor's open and close braces.

The default constructor for the base class is executed if the subclass makes no explicit reference to a different constructor. Thus, in the following code snippet, the Pig base class is constructed before any members of LittlePig, even though LittlePig makes no explicit reference to that constructor:

class House {};
class Pig
Pig() : pHouse(nullptr) {}
House* pHouse;
class LittlePig : public Pig
LittlePig(double volStraw, int numSticks,
int numBricks)
: straw(volStraw), sticks(numSticks),
bricks(numBricks) { }

double straw;
int sticks;
int bricks;

Similarly, the copy constructor for a base class is invoked automatically.

Destructing a subclass

Following the rule that destructors are invoked in the reverse order of the constructors, the destructor for GraduateStudent is given control first. After it’s given its last full measure of devotion, control passes to the destructor for Advisor and then to the destructor for Student. If Studentwere based on a class Person, the destructor for Person would get control after Student.

This is logical. The blob of memory is first converted to a Student object. Only then is it the job of the GraduateStudent constructor to transform this simple Student into a GraduateStudent. The destructor simply reverses the process.

Inheriting constructors

image As of the 2011 standard, subclass can inherit the constructor of its base class as well, as shown in the following snippet:

class Student
Student(string name);
class GraduateStudent : public Student
using Student::Student; // inherit base constructors

This creates a GraduateStudent(string) constructor exactly as if the following had been entered:

class GraduateStudent : public Student
GraduateStudent(string name) : Student(name) {}

The advantage of inheriting the constructors of the base class is that the subclass inherits all of the base class constructors. This is useful when building a subclass that extends an important base class in some trivial way.

Having a HAS_A Relationship

Notice that the class GraduateStudent includes the members of class Student and Advisor, but in a different way. By defining a data member of class Advisor, you know that a Student has all the data members of an Advisor within it. However, you can’t say that a GraduateStudent is anAdvisor — instead you say that a GraduateStudent HAS_A Advisor. What’s the difference between this and inheritance?

Use a car as an example. You could logically define a car as being a subclass of vehicle, so it inherits the properties of other vehicles. At the same time, a car has a motor. If you buy a car, you can logically assume that you are buying a motor as well. (Unless you go to the used-car lot where I got my last junk heap.)

If friends ask you to show up at a rally on Saturday with your vehicle of choice and you go in your car, they can't complain (even if someone else shows up on a bicycle) because a car IS_A vehicle. But, if you appear on foot carrying a motor, your friends will have reason to laugh at you because a motor is not a vehicle. A motor is missing certain critical properties that all vehicles share — such as a place to ride.

From a programming standpoint, the HAS_A relationship is just as straightforward. Consider the following:

class Vehicle {};
class Motor {};
class Car : public Vehicle
Motor motor;

void VehicleFn(Vehicle& v);
void MotorFn(Motor& m);

int main(int nNumberofArgs, char* pszArgs[])
Car car;
VehicleFn(car); // this is allowed
MotorFn(car); // this is not allowed
MotorFn(car.motor);// this is allowed
return 0;

The call VehicleFn(c) is allowed because car IS_A vehicle. The call MotorFn(car) is not because car is not a Motor, even though it contains a Motor. If the intention were to pass the Motor portion of c to the function, this must be expressed explicitly, as in the call MotorFn(car.motor).