Derived Classes
Most object oriented languages provide at least two ways to reuse classes. End-users can create new functions and classes that contain references to instances of existing classes. This is called composition. For example, the stack calculator uses instances of a stack class. Any stack class will do, as long as it correctly implements push(), pop(), and top().
This is fine if instances of the existing class provide exactly the services and attributes required, but what if more features are required, or what if existing features need to be modified? Value-adders can create new classes that have features that extend or alter the features of an existing class. In this case we say the new class extends or is derived from the existing class. The derived class inherits the variables and member functions of the base class.
For example, assume an Employee class has been defined:
class Employee
{
public:
Employee(string nm = "?",
string id = 0,
float sal = 0,
int ded = 1)
{
name = nm;
ssn = id;
salary = sal;
deductions = ded;
}
string getName() const { return name; }
void setName(const string& nm) { name = nm; }
string getSSN() const { return ssn; }
void setSSN(const string& id) { ssn = id; }
double getSalary() const { return salary; }
void setSalary(const double sal) { salary = sal; }
int getDeductions() const { return deductions; }
void setDeductions(const int ded) { deductions = ded; }
ostream& print(ostream& os = cout)
{
os << "Name \t= \t" << name << '\n';
os << "SSN \t= \t" << ssn << '\n';
os << "salary \t= \t" << salary << '\n';
os << "deductions \t= \t" << deductions << '\n';
return os;
}
private:
string name;
string ssn;
float salary;
int deductions;
};
An end user can use instances of the Employee class to build new classes:
class Company
{
public:
void addEmployee(Employee* e)
{
staff.push_back(e);
}
ostream& print(ostream& os = cout)
{
for(int i = 0; i < staff.size(); i++)
os = staff[i]->print(os);
return os;
}
private:
vector<Employee*> staff;
};
But what if we require special representations for specific types of employees: programmers, secretaries, managers, etc.? We don't want to throw away our Employee class (and the classes that depend on it).
The solution is to create new classes that extend the Employee class. We can extend a class using the syntax:
class Derived: public Base { ... };
where Base is an existing class, and Derived is a new class. Here are two examples:
class Secretary: public Employee
{
public:
Secretary(string nm = "?", string id = 0, float sal = 0,
int ded = 1, int speed = 0);
int getWPM() { return wpm; }
void setWPM(int speed) { wpm = speed; }
ostream& print(ostream& os = cout);
private:
int wpm; // typing speed in words/minute
};
class Manager: public Employee
{
public:
Manager(string nm = "?", string id = 0, float sal = 0,
int ded = 1, int lev = 0, Secretary* s = 0);
int getLevel() { return level; }
void setLevel(int lev) { level = lev; }
Secretary* getSecretary() { return sec; }
void setSecretary(Secretary* s) { sec = s; }
ostream& print(ostream& os = cout);
private:
int level; // 2 = hi, 1 = mid, 0 = low
Secretary* sec;
};
Instances of a derived class inherit the functions and variables of the base class. For example, although smith is an instance of Secretary, we can still invoke the getSalary() function inherited from the base class:
Secretary smith("Joe Smith", "111-11-1111", 40000, 3, 60);
cout << '$' << smith.getSalary() << '\n'; // prints $40000
Secretary has two print() functions, Employee::print() is inherited from the base class, and Secretary::print() is defined in the derived class. Calling the print() function calls using smith as an implicit parameter calls Secretary::print():
smith.print(); // calls Secretary::print()
Does this mean we lose our inheritance? Not at all, Secretary::print() and Manager::print() can actually call the inherited Employee::print() by using the scope resolution operator:
ostream& Secretary::print(ostream& os /* = cout */)
{
os = Employee::print(os);
os << "Position \t=\t" << "secretary\n";
os << "WPM \t=\t" << wpm << '\n';
return os;
}
ostream& Manager::print(ostream& os /* = cout */)
{
os = Employee::print(os);
os << "Position \t=\t" << "manager\n";
os << "Level \t=\t" << level << '\n';
os << "Secretary:\n";
os = sec->print(os);
return os;
}
Upcasting and Downcasting
Assume the following objects are declared:
Employee wong("Ted Wong", "987-65-4321", 50000);
Secretary smith("Joe Smith", "111-11-1111", 40000, 3, 60);
Every instance of Manager or Secretary can be upcast to an instance of Employee, but an instance of Employee can't be downcast to an instance of Secretary:
Employee(smith).print(); // ok, but Employee::print() is called
cout << Secretary(wong).getSalary() << '\n'; // error
C++ isn't as careful with pointers. For example, assume wong is a pointer:
Employee* wong = new Employee("Ted Wong", "987-65-4321", 50000);
The following downcasts are allowed by the compiler, but produce weird results at runtime:
cout << ((Secretary*)wong)->getSalary() << '\n'; // prints 50000
cout << ((Secretary*)wong)->getWPM() << '\n'; // prints gibberish
Object Layout
We can see what's going on by drawing object diagrams of smith and wong:

Upcasting a secretary to an employee is easy, just truncate the wpm variable. The type checker is too smart to allow a downcast from Employee to Secretary, but a pointer to an Employee might actually be a pointer to a Secretary. For example, assume the following declaration is made:
Employee* smith =
new Secretary("Joe Smith", "111-11-1111", 40000, 3, 60); // ok
These downcasts work:
cout << ((Secretary*)smith)->getSalary() << '\n'; // prints 40000
cout << ((Secretary*)smith)->getWPM() << '\n'; // prints 60
Derived Class Constructors
Constructing an instance of Manager or Secretary is tricky. How will the private member variables of the base class be initialized? We can't initialize them in the body of the Manager constructor because they are private. If a base class has any constructor, then one must be called. The solution is similar to the solution used to initialize member objects, constants, and reference: place a call to a base class constructor in the initializer list:
Manager::Manager(string nm, string id, float sal,
int ded,int lev, Secretary* s )
:Employee(nm, id, sal, ded)
{
sec = s;
level = lev;
}
Secretary::Secretary(string nm, string id, float sal,
int ded, int speed)
:Employee(nm, id, sal, ded)
{
wpm = speed;
}
More UML Notation
Inheritance is indicated in UML diagrams using the generalization arrow:

Multiple Inheritance
C++ allows multiple inheritance:
class CEO: public Employee, public StockHolder
{
// etc.
};
As you would expect, CEO class inherits from both the Employee class and the StockHolder class.
Programmers must resolve ambiguities that arise from inheriting member functions with the same name. For example, assume Employee and StockHolder both implement a print() function:
ostream& Employee::print(ostream& os);
ostream& StockHolder::print(ostream& os);
CEO member functions must indicate which function they are calling by using the scope resolution operator:
void CEO::display()
{
Employee::print(cout); // ok
StockHolder::print(cout); // ok
print(cout); // error, ambiguous
}
Complications arise when a class inherits from two classes with a common base class. For example, assume:
class StockHolder: public Person { ... };
class Employee: public Person { ... };
where:
class Person
{
string name, address, phone;
// etc.
};
Here's the structure:

A CEO object inherits Person attributes from its Employee base and its StockHolder base:

It's possible that the addresses or phone numbers can get out of synch. These problems can be partially solved by declaring Employee and StockHolder virtual base classes of CEO:
class StockHolder: virtual public Person { ... };
class Employee: virtual public Person { ... };
This creates a single copy of the Person data and pointers from the Employee and StockHolder data:

Programming with virtual base classes introduces a whole new batch of headaches. We'll come back to these later.
Inner Classes
In addition to functions and variables, classes can also contain types. We call these inner types. An inner type that's a class is called an inner class. Like static members, inner types are associated with the outer class, not individual members of the outer class. For example, assume the following declarations is made:
class AAA
{
public:
class BBB { ... };
// etc.
};
To declare a variable of type BBB, a client must qualify the type name using the scope resolution operator:
AAA::BBB x;
Use inner types when you want to tie the inner type to types or statics defined in the outer type or when you don't want people to see the inner types:
class Computer
{
public:
Computer() { cpu = Processor(this); }
private:
enum Sizes { KBYTES = 24, KBYTE = 1024 };
typedef unsigned Word;
typedef unsigned* Address;
typedef unsigned Memory[KBYTE * KBYTES];
class Processor
{
public:
Processor() {}
Processor(Computer* comp)
{
myComputer = comp;
pc = myComputer->memory;
sp = myComputer->memory + sizeof(Memory);
}
void run(); // fetch-execute cycle
void execute(Word inst);
private:
Address sp, pc;
Word reg1, reg2, reg3; // registers
Computer* myComputer;
ostream& kbd; // = cin
istream& monitor; // = cout
};
public:
friend class Processor;
void store(Word w, Address addr) { *addr = w; }
Word fetch(Address addr) { return *addr; }
void start() { cpu.run(); }
private:
Memory memory;
Processor cpu;
};
Note how names of inner class members are qualified:
void Computer::Processor::run()
{
while(true)
{
Word instruction = myComputer->fetch(pc++);
execute(instruction);
}
}
void Computer::Processor::execute(Word instr)
{
if (instr == 0) // Read Reg1, [PC++]
reg1 = myComputer->fetch(pc++);
else if (instr == 1) // Write Reg1, [PC++]
myComputer->store(reg1, pc++);
else if (instr == 2) // Add Reg3, Reg1, Reg2
reg3 = reg1 + reg2;
// etc.
else
error("unrecognized instruction\n");
}
Problems
Problem
Debug and complete the Computer class. Test your implementation by using it to compute the factorial function:
n! = n * (n – 1) * ... * 1
Problem
A bordered grid is a grid with a border around it
________________________
| |
| Hello |
| |
| |
| |
| |
| |
| |
| |
| |
-----------------------
Each unplotted point in a shaded grid contains a shade character:
////////////////////////
////////////////////////
///Hello////////////////
////////////////////////
////////////////////////
////////////////////////
////////////////////////
////////////////////////
////////////////////////
////////////////////////
////////////////////////
////////////////////////
A bordered shaded grid is both a shade grid and a bordered grid:
________________________
|//////////////////////|
|//Hello///////////////|
|//////////////////////|
|//////////////////////|
|//////////////////////|
|//////////////////////|
|//////////////////////|
|//////////////////////|
|//////////////////////|
|//////////////////////|
|//////////////////////|
________________________
Implement ShadeGrid and BorderedGrid as derived classes of Grid (from the previous chapter). Implement BorderedShadeGrid as a derived class from BorderedGrid and ShadeGird:

Test your implementations.