This is the facility that lets a class be derived from another class. The example that all the C++ books choose is that of birds, and I am no exception. Consider the following:
"All parrots are birds. Most birds can fly but some can't. All penguins are also birds. Some parrots are wild, some are domesticated. The domesticated parrots have names."
Each of the boxes in the diagram can be implemented as a class, with its own member variables and member functions. We will use inheritance to link them together.
class animal
{ public:
int warmblooded; // 1 means yes, 0 means no
int numlegs;
int colour_vision; // Applies to apes, birds, fish
// and insects. A funny mix!
};
class bird : public animal
{ public:
int hasfeathers; // 1 means yes, 0 means no
// Well, it could be a Sainsbury's frozen chicken!
int canfly;
string diet;
int IQ;
public:
// Constructor for the bird class
bird ()
{ warmblooded = 1;
numlegs = 2;
colour_vision = 1;
}
};
class parrot : public bird
{ public:
int cantalk;
};
class domestic_parrot
{ public:
string name;
};
domestic_parrot polly;
After each of the class names (except the one for animal which is at the top of the heap, there is a colon and the word public and the name of the class from which this particular class is derived. The class bird is derived from the class animal, and parrot is a class derived from bird. We say that bird is the base class for parrot, and animal is the base class for bird. Get the idea?
The thing is that the derived classes inherit all the member variables and functions of their base classes, so the class bird inherits the member variables from the class animal. Similarly, the class domestic_parrot inherits all the member variables from the classes animal, bird and parrot from which it is derived.
You probably wondered why the class bird had a constructor function that set variables like warmblooded and numlegs which weren't declared directly in it. However, since bird is derived from animal and these variables are public member variables of class animal, the constructor can alter them. It would be a different matter had the code been defined as follows:
class animal
{ private:
int warmblooded; // 1 means yes, 0 means no
int numlegs;
int colour_vision;
};
class bird : public animal
{ public:
int hasfeathers;
int canfly;
string diet;
int IQ;
public:
// Constructor for the bird class
bird ()
{ warmblooded = 1; // Ah! Naughty, naughty!
numlegs = 2;
colour_vision = 1;
}
};
Now the variables are private members of the class animal and no class derived from it can alter them except through any get or set function which the class animal may provide. I haven't put either of those two functions in, so the variables are effectively locked away. Silly me! The same would apply to code defined as follows:
class animal
{ public:
int warmblooded; // 1 means yes, 0 means no
int numlegs;
int colour_vision;
};
class bird : private animal
{ public:
int hasfeathers;
int canfly;
string diet;
int IQ;
public:
// Constructor for the bird class
bird ()
{ warmblooded = 1; // Ah! Naughty, naughty!
numlegs = 2;
colour_vision = 1;
}
};
This time all the member variables in the class animal are private as far as the derived class bird is concerned, and out of bounds. Any variable which is declared to be of type animal can treat the variables as public:
animal fido; fido.numlegs = 4; // Perfectly legal
Let's go back to the original version of the code, with all the member variables public and all classes being derived publicly. You will find that member functions are also inherited.
For example, the constructor I have included automatically executes when any variable is declared of type bird, parrot or domestic_parrot. It executes when the variable polly is declared, so Polly will automatically have two legs, warm blood etc. Add the following member function to the class bird:
public:
void say_something ()
{ cout << "Tweet, tweet!" << endl;
}
Now add the following member function to the class parrot:
public:
void say_something ()
{ cout << "Squark! Who's a pretty boy, then!" << endl;
}
Now, consider the following statement:
polly.say_something();
This is legal. The class domestic_parrot is derived from not only one but two classes which have an appropriately named member function. But what exactly will Polly say?
The answer is that C++ backtracks up the tree until it finds an appropriately named function. Then it executes that function and stops looking. In this case, the first appropriate function it comes across is the one in class parrot, so the result is Squark! Who's a pretty boy then!