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 and 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); 

void finish(Student* student) {
    cout << "\nThe following "
         << student->getClassName()
         << " has applied for graduation.\n "
         << student->toString() << "\n";
}

int main() {
    Undergrad us("Frodo Baggins", 5562, "Ring Theory", 4, 1220);
    GradStudent gs("Bilbo Baggins", 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 finish their studies:\n";
    finish(&us);
    finish(&gs);
    return 0;
}

<include src="src/derivation/qmono/student-test.cpp" href="src/derivation/qmono/student-test.cpp" mode="cpp" id="src-qmonoclient"/>


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

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

Then run it like this:

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

[Student] name: Frodo Baggins; Id: 5562; Year: senior;
  Major: Ring Theory  [SAT: 1220 ]

Here is what happens when they finish their studies:

The following Student has applied for graduation.
 [Student] name: Frodo Baggins; Id: 5562; Year: senior; 
   Major: Ring Theory
   
The following Student has applied for graduation.
 [Student] name: Bilbo Baggins; Id: 3029; Year: gradual student;
   Major: History
src/derivation/qmono>

In the finish() function, the parameter, student, is a base class pointer. Calling student->toString() invokes Student::toString() regardless of what kind of object student points to. But, for example, if student points to a GradStudent, there should be a mention of the fellowship in the output message. In addition, you should see "[GradStudent]" in the toString() messages, and you do 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.



[45] It would be nice if the output showed [GradStudent] here.