6.1.1.  Inheritance Client Code Example

[ fromfile: inheritance-intro.xml id: inheritanceclientcode1 ]

GradStudent is a Student, in the sense that a GradStudent object can be used wherever a Student object can be used. The client code shown in Example 6.5 creates some instances and performs operations on a GradStudent or an Undergrad instance directly and also indirectly, through pointers.

Example 6.5. src/derivation/qmono/student-test.cpp

#include <QTextStream> 
#include "student.h"

static QTextStream cout(stdout, QIODevice::WriteOnly); 

void graduate(Student* student) {
    cout << "\nThe following "
         << student->getClassName()
         << " has graduated\n "
         << student->toString() << "\n";
}

int main() {
    Undergrad us("Frodo", 5562, "Ring Theory", 4);
    GradStudent gs("Bilbo", 3029, "History", 6, GradStudent::fellowship);
    cout << "Here is the data for the two students:\n";
    cout << gs.toString() << endl;
    cout << us.toString() << endl;
    cout << "\nHere is what happens when they graduate:\n";
    graduate(&us);
    graduate(&gs);
    return 0;
}

To build this application we use qmake and make as follows:

src/derivation/qmono> qmake -project 
src/derivation/qmono> qmake 
src/derivation/qmono> make 
   

We then can run it like this:

src/derivation/qmono> ./qmono
Here is the data for the two students:
[Student] [22] name: Bilbo Id: 3029 Year: gradual student Major: History
  [Support: fellowship ]

[Student] name: Frodo Id: 5562 Year: senior Major: Ring Theory

Here is what happens when they graduate:

The following Student has graduated
 [Student] name: Frodo Id: 5562 Year: senior Major: Ring Theory

The following Student has graduated
 [Student] name: Bilbo Id: 3029 Year: gradual student Major: History
src/derivation/qmono>

Calling student->toString() from the function graduate() invokes Student::toString() regardless of what kind of object student points to. If the object is, in fact, a GradStudent, then there should be a mention of the fellowship in the graduation message. In addition, we should be seeing “[GradStudent]“ in the toString() messages, and we are not.

It would be more appropriate to use runtime binding for indirect function calls to determine which toString() is appropriate for each object.

Because of its C roots, C++ has a compiler that attempts to bind function invocations at compile time, for performance reasons. With inheritance and base class pointers, the compiler can have no way of knowing what type of object it is operating on. In the absence of runtime checking, an inappropriate function can be called. C++ requires the use of a special key word to enable runtime binding on function calls via pointers and references. The keyword is virtual, and it enables polymorphism, which is explained in the next section.



[22] it would be nice if we saw [GradStudent] here