class DisplayableNumber {...}; // base class class Counter : public DisplayableNumber {...}; // derived class class Cycler : public DisplayableNumber {...}; // derived classThe additional syntax " : public DisplayableNumber" is used in the definition of each derived class to name the base class from which the derived class inherits. The keyword "public" in this context means that all of the public methods defined in the base class (DisplayableNumber) become part of the public interface of the derived class (Counter, Cycler). These inherited methods represent the code sharing that is achieved by inheritance.
The public interface of the three classes DisplayableNumber, Counter and Cycler are as follows:
class DisplayableNumber { public: DisplayableNumber(int init = 0); // initial value zero by default void ShowIn(TextBox& p); void Show(); void Reset(); int Value(); ~DisplayableNumber(); }; class Counter : public DisplayableNumber { public: Counter(int init = 0); void Next(); ~Counter(); }; class Cycler : public DisplayableNumber { public: Cycler(int b, int init = 0); void Next(); ~Cycler(); };The critical point is that, through inheritance, Counter and Cycler objects have not only those methods defined in the Counter and Cycler classes, but also those methods inherited from the public interface of the base class, DisplayableNumber. For example:
Counter count(10); // initially 10 Cycler binary(2); // base 2 TextBox display(Location(10,10), Shape(50,50)); TextBox onoff (Location(20,20), Shape(50,50)); count.ShowIn(display); binary.ShowIn(onoff); count.Next(); // increment by 1 binary.Next(); // increment by 1 modulo 2 count.Show(); // display updated value binary.Show(); // display updated value int c = count.Value(); // get value of Counter object int b = binary.Value(); // get value of Cycler objectAs shown in this example, the Counter and Cycler objects can respond both to the methods defined in their immediate classes (Next) and also to the inherited methods (ShowIn, Show, Reset and Value) that are defined in the base class DisplayableNumber.
Data can also be placed in the base class. In the example above, the value and textBox variables are common to both the Counter and Cycler classes. This data should be promoted to the base class. The variable textBox is used only in the methods ShowIn, Show and Reset, all of which are in the base class (DisplayableNumber). Thus, the textBox variable can be placed in the private data area of the base class. The variable value, however, is needed in both the base class (where it is used by the Show and Reset methods) and in the derived class (where it is used in the Next method).
Data to be shared between the base and derived classes is placed in a new region, the "protected" regions, in the base class. Data placed in this new region is accessible both to the base class and to the derived classes. Similar to the "private:" and "public:" regions, the new region is introduced by the keyword "protected:".
The protected region is needed because neither the private nor public regions are adequate places to put the shared data. If the shared data is placed in the private region of the base class the data is inaccessible to the derived classes. This is, of course, contrary to what is needed. If the shared data is placed in the public region of the base class then it is accessible to the derived classes but it is also accessible as public data in the interface of the derived class. This means that the data looses its encapsulation and is exposed to the user of the objects created from the derived class. This is also contrary to what is needed.
The protected region contains data (and operations) that are accessible to the base class, accessible to the derived class, and inaccessible everywhere else. Protected data (and operations) are not part of the public interface of either the base class or the derived classes.
The class definition, including the data private and protected data, for the DisplayableNumber base class is:
class DisplayableNumber { private: TextBox* textBox; // place to display value protected: // the following are accessible in derived classes int value; // internal counter public: DisplayableNumber(int init); // initial value void ShowIn(TextBox& p); void Show(); void Reset(); int Value(); // reply current value ~DisplayableNumber(); };Notice that the base class DisplayableNumber forms a complete class - it defines an unchanging integer number that can be dispalyed in a TextBox. In some limited cases this may be all that is needed. For example, a portion of an interactive testing system may need to display a final score to the user as follows:
TextBox scoreBox(Location(100,100), Shape(75, 50)); int score; // interact with user; determine final score DisplayableNumber finalScore(score); finalScore.ShowIn(scoreBox); finalScore.Show();The classes derived from DisplayableNumber introduce the ability to change the number dynamically. Each new derived class embodies a different way to change the value.
The constructors for derived classes, like the Counter and Cycler classes, must be related to the constructors of their base classes, like DisplayableNumber. The constructor for the Counter class has an integer argument that should be used to initialize the Counter's internal "value". However, the DisplayableNumber class also has a constructor for that purpose. In this case, the Counter's constructor argument should simply be passed on to the DisplayableNumber's constructor. The C++ syntax for this is:
Counter::Counter(int init) : DisplayableNumber(init) { }The additional syntax ": DisplayableNumber(init) " means that the derived class constructor argument (init) is used as the base class constructor argument. In this case, no other initialization is done in the derived class (the body of the constructor has no code).
The Cycler class illustrates a different relationship between the constructors of the derived and base classes. The first integer value for the Cycler's constructor is the base of the Cycler and the second integer value is the initial value of the Cycler. This is reflected in the Cycler's constructor as follows:
Cycler::Cycler(int b, int init) : DisplayableNumber(init) { base = b; }In this case some of the derived class's constructor arguments are used to construct the base class while otheres are used to initialize the data in the derived class itself.
Having declared the protected data in the base class, the code for the derived classes is:
class Counter : public DisplayableNumber { public: Counter(int init = 0); void Next(); ~Counter(); }; class Cycler : public DisplayableNumber { private: int base; public: Cycler(int b, int init = 0); void Next(); ~Cycler(); };and the code for the methods of these classes is:
Counter::Counter(int init) : DisplayableNumber(init) { } void Counter::Next() { value = value + 1; } Counter::~Counter() {} Cycler::Cycler(int b, int init) : DisplayableNumber(init) { base = b; } void Cycler::Next() { value = (value + 1)%base; } Cycler::~Cycler() {}