[ 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.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |