COEN244: Polymorphism Aishy Amer Electrical & Computer Engineering Polymorphism means “variable behavior”/“ability to appear in many forms” Outline Casting between objects Using pointers to access objects Static polymorphism: compile-time type and function checking Dynamic polymorphism: run-time type and function checking Virtual functions: can be over-ridden at run time Pure Virtual functions: must be over-ridden Abstract Classes: classes with at least one pure virtual function Virtual destructor c A. Amer Polymorphism 1
97
Embed
Aishy Amer - EncsStatic polymorphism: compile-time type and function checking Dynamic polymorphism: run-time type and function checking Virtual functions: can be over-riddenat run
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
COEN244: Polymorphism
Aishy Amer
Electrical & Computer Engineering
Polymorphism means “variable behavior”/“ability to appear in many forms”
OutlineCasting between objects
Using pointers to access objects
Static polymorphism: compile-time type andfunction checking
Dynamic polymorphism: run-time type andfunction checking
Virtual functions: can be over-ridden at run
time
Pure Virtual functions: must be over-ridden
Abstract Classes: classes with at least onepure virtual function
Casting: conversion from one data type to another typec o n v e r t t o t y p e ( express ion ) ;// Example :t = i n t ( x ) ; q=double ( y ) ;
Standard numerical conversions are used forintegral promotions (e.g., enum to int)integral conversions (e.g., int to unsigned int)floating point conversions (e.g., float to double)floating-integral conversions (e.g., int to float)arithmetic conversions(e.g., converting operands to the type of the widestoperand before evaluation)
Some conversions are performed automatically by thecompiler without intervention by the programmerStandard C++ conversions and user-defined conversionsare performed implicitly by the compiler where neededExamples?
Explicit conversions:
Conversions which must be explicitly specified by theprogrammer
All casting operators have the same syntax:stat ic_cast conver t_ to_type ( expr ) ;/ / ==> Convert expr to type conver t_ to_typestat ic_cast <DerivedClass ∗> ( PointerToBaseObj )
Use the least dangerous (most specific) casting alternative
const i n t x =5;const i n t ∗ pX ; / / changeable p o i n t e r to constant i n t∗pX = 3; / / i l l e g a l − can ’ t use pX to modify an i n tpX = &someOtherIntVar ; / / l e g a l − pX can po in t somewhere e lse
i n t ∗ const pY ; / / constant p o i n t e r to changeable i n t∗pY = 4; / / l e g a l − can use pY to modify an i n tpY = &someOtherIntVar ; / / i l l e g a l − can ’ t make pY po in t anywhere e lse
const i n t ∗ const pZ ; / / const p o i n t e r to const i n t∗pZ = 5; / / i l l e g a l − can ’ t use pZ to modify an i n tpZ = &someOtherIntVar ; / / i l l e g a l − can ’ t make pZ po in t anywhere e lse
double q = x / y ; / / c l a s s i c mistake , r e s u l t i s rounded to an i n tcout << q ; / / p r i n t s " 4.000000"double q = ( double ) x / y ; / / cast r e s u l t as double so i t ’ s not roundedcout << q ; / / p r i n t s "4.625000"
/ / Bas cas t ing : fo rce the compi ler to put the address o f/ / a const i n t v a r i a b l e i n t o a normal i n t ∗const i n t x = 4; / / x i s const , i t can ’ t be modi f iedconst i n t ∗ pX = &x ; / / you can ’ t modify x through the pX p o i n t e rcout << x << endl ; / / p r i n t s "4 "
i n t ∗ pX2 = ( i n t ∗ )pX ; / / e x p l i c i t l y cast pX as an i n t ∗∗pX2 = 3; / / r e s u l t i s undef ined
cout << x << endl ; / / who knows what i t p r i n t s ?/ / The code compiles and runs w i thou t crashing , but who knows what i s x
/ / The Const_cast Operatorconst i n t x = 4; / / x i s const , i t can ’ t be modi f iedconst i n t ∗ pX = &x ; / / you can ’ t modify x through the pX p o i n t e r
cout << x << endl ; / / p r i n t s "4 "
i n t ∗ pX2 = const_cast < i n t ∗ > (pX ) ; / / e x p l i c i t l y cast pX as non−const
∗pX2 = 3; / / r e s u l t i s undef inedcout << x << endl ; / / who knows what i t p r i n t s ?
/ / With const_cast : change the const−ness of a va r iab le , and never i t s type
Object casting is used forpointer conversion(e.g., derived class pointer to base class pointer)reference conversion(e.g., derived class reference to base class reference)pointer-to-member conversion(e.g., from pointer to member of a base class to pointer tomember of a derived class)
A conversion from type SS to TT can ONLY be done if
the conversion from type TT to SS is an implicit conversion
Down-casting:convert a base class pointer to a derived class pointeronly if the conversion is unambiguous(& base class is non-polymorphic)
Example:c l a s s BankAcct { . . . } ;c l a s s SavingsAcct : public BankAcct { . . . } ;
/ / Given a b a s e c l a s s p o i n t e r ,/ / we can c a s t i t t o a d e r i v e d c l a s s p o i n t e r :void foo ( BankAcct∗ a c c t ) {SavingsAcct∗ d1 = s t a t i c c a s t <SavingsAcct∗> ( a c c t ) ;}
static cast : no run-time type checking→ if acct does not refer to an actual SavingsAcctthen the result of the cast is undefined
Applied to pointers to objects:Cast a pointer of a derived class to its base classCast a pointer of a base class to its derived class• The base class that is being casted is not checked to
determine whether this is a complete class of thedestination type or not:
c l a s s Base { . . . } ;c l a s s Derived : public Base { . . . } ;Base ∗ a = new Base ;Derived ∗ b = s t a t i c c a s t <Derived∗> ( a ) ;
class C i r c l e : public Poin t {f r iend ostream& operator <<(ostream&, C i r c l e &) ;public :
C i r c l e ( f l o a t = 0.0 , i n t = 0 , i n t = 0 ) ;void setRadius ( f l o a t ) ; / / access der i ve par t s on lyi n t getRadius ( ) const { return r ; }f l o a t area ( ) const { return PI∗ r ∗ r ; }protected :
f l o a t r ;} ;
C i r c l e : : C i r c l e ( f l o a t rad , i n t a , i n t b ) : Po in t ( a , b ) { setRadius ( rad ) ; }
Poin t p (4 , 5 ) , ∗ p o i n t P t r ;C i r c l e c (0 .707 , 1 , 2 ) , ∗ c i r c l e P t r ;
/ / Assign C i r c l e ob jec t to Po in t ob jec t p o i n t e r/ / Can only access the Po in t i n f o !p o i n t P t r = &c ;
/ / Since p o i n t P t r r e a l l y po in t s to a C i rc le , we can/ / cast i t back to a C i r c l ec i r c l e P t r = stat ic_cast < C i r c l e ∗ >( p o i n t P t r ) ;cout << ∗ p o i n t P t r ; / / Ca l l operator << f o r Po in t/ / Output : ( x , y )= 1 2
cout << ∗ c i r c l e P t r ; / / Ca l l operator << f o r C i r c l e/ / Output : ( x , y , r )= 1 2 0.707
Poin t p (4 , 5 ) , ∗ p o i n t P t r ;C i r c l e c (0 .707 , 1 , 2 ) , ∗ c i r c l e P t r ;
/ / Assign C i r c l e ob jec t to Po in t ob jec t p o i n t e r/ / Can only access the Po in t i n f o !p o i n t P t r = &p ;
/ / ! ! ! ! ! ! Can I do t h i s ?c i r c l e P t r = stat ic_cast < C i r c l e ∗ >( p o i n t P t r ) ;cout << ∗ p o i n t P t r ; / / Ca l l operator << f o r Po in t/ / Output : ( x , y )= 4 5
cout << ∗ c i r c l e P t r ; / / Ca l l operator << f o r C i r c l e/ / Output : ( x , y , r )= 4 5 ’ garbage ’
/ / L i s t i n g 15.1 Using po in te r s to access ob jec ts o f base and der ived classesclass Base { / / base c lass
protected : i n t x ;public :Base ( i n t a ) { x = a ; } / / to be used by Derivedvoid set ( i n t a ) { x = a ; } / / to be i n h e r i t e di n t show ( ) const { return x ; } / / to be i n h e r i t e d
} ;
class Derived : public Base { / / der ived c lassprivate : i n t y ;public :
Derived ( i n t a , i n t b ) : Base ( a ) , y ( b ){ } / / empty cons t ruc to r body
void access ( i n t &a , i n t &b ) const / / added i n der ived c lass{ a = Base : : x ; b = y ; }
i n t x , y ;Derived ∗pD = new Derived (50 ,80 ) ; / / unnamed der ived ob jec t
cout << " 1 . Derived po in te r , ob jec t , and der ived method \ n " ;pD−>access ( x , y ) ; / / no problem : type matchcout <<" x = " <<x <<" y = " <<y <<endl <<endl ; / / x=50 y=80
cout << " 2 . Derived po in te r , der ived ob jec t , base method \ n " ;cout << " x = " << pD−>show ( ) << endl << endl ; / / x = 50Base ∗pB = pD; / / p o i n t e r to same ob jec t
cout << " 3 . Base po in te r , der ived ob jec t , base method \ n " ;cout << " x = " << pB−>show ( ) << endl << endl ; / / x = 50/ / pB−>access ( x , y ) ; / / e r r o r : no access to der ived method
cout << " 4 . Converted po in te r , der ived ob jec t and method \ n " ;( ( Derived ∗ ) pB)−>access ( x , y ) ; / / we know i t i s therecout <<" x = " <<x <<" y = " <<y <<endl <<endl ; / / x=50 y=80pB = new Base ( 6 0 ) ; / / unnamed base ob jec t
cout << " 5 . Base po in te r , base ob jec t , base method \ n " ;cout << " x = " << pB−>show ( ) << endl <<endl ; / / x = 60
cout << " 6 . Converted po in te r , base ob jec t , der ived method \ n " ;( ( Derived ∗ ) pB)−>access ( x , y ) ; / / pass on your own r i s kcout <<" x = " <<x <<" y = " <<y <<endl <<endl ; / / junk ! !
delete pD; delete pB ; / / necessary t i d i n e s s
An object is denoted by its name (identifier) and the typeassociated with this identifier
Polymorphism (dynamic binding, virtual function):The principle that behavior of a function can varydepending on the actual type of an object
With polymorphism:Objects of different classes related by inheritance mayrespond differently to the same member function callThis allows a programmer to manipulate an object withoutknowing what kind of object it is
Static polymorphism – (static binding or early binding):At compile time (at the earliest possible time):the compiler selects a method from several candidatesSelection is based on the type of the pointer to the object
Static polymorphism – (static binding or early binding):At compile time (at the earliest possible time):the compiler selects a method from several candidatesSelection is based on the type of the pointer to the object
Dynamic polymorphism – (dynamic binding or late binding):At run time (at the latest possible time):the compiler selects a method from several candidatesBased on the type of the objectThis allows a programmer to manipulate an object withoutknowing what kind of object it is
Recall: In a derived class,you can redefine (this is?) functions of the base class⇒ compile-time solution
Static polymorphism (early binding):When the compiler selects a method from severalpossible candidates at compile timeThe legality of the implementation(e.g., a member function invocation)is checked at compile timeExample: if Vehicle has a certain member function,Car also has that member function
Dynamic polymorphism (late binding):When the compiler selects a method from severalpossible candidates at run timeThe legality of some types and functions is determinedbased on the dynamic type of the object at run time
Dynamic polymorphism is implemented through virtual functions
Dynamic polymorphism (late binding):When the compiler selects a method from severalpossible candidates at run timeThe legality of some types and functions is determinedbased on the dynamic type of the object at run time
Also called "dynamic binding":the binding to the code that gets called is accomplisheddynamically (at run time)
Dynamic polymorphism is implemented through virtual functions
So: when you have a pointer to an object,this actual object may be of a derived class
A pointer to an object of type Vehicle*maybe actually be pointing to a Car objectA pointer to an object of type Shape*maybe actually be pointing to a Rectangle object
So: when you have a pointer to an object,this actual object may be of a derived class
A pointer to an object of type Vehicle*maybe actually be pointing to a Car objectA pointer to an object of type Shape*maybe actually be pointing to a Rectangle object
Dynamic binding implies that a base class pointer figures outwhich derived class it really points to at run-time
Before OOP: software reuse when new code call old code
Dynamic binding can improve reuse by letting old code callnew code
Dynamic binding permits software extensibility:With OOP: a new code may be created, compiled, andtestedLater, this code can be called by a framework that waswritten long time agoThere is no need to change the old code:it does not even need to be recompiled
Dynamic binding does not make static binding irrelevant
It introduces many additional dimension of complexity
poly.method(...); OR poly->method(...);
Check if the target (here poly) is an object or a pointerIf it is an object:• Only static binding possible• Check the function signature and• Verify if the function call is correctIf the target is a pointer: consider dynamic binding
In most cases: the method being called depends on the typeof the pointer not on the type of the object
If the target is a pointer: consider dynamic bindingDefine at which place in the inheritance hierarchy thepointer belongsIf the pointer is of the derived type:only static binding is possibleIf the pointer is of the base type:dynamic binding is possible
If the pointer is of the base type: dynamic binding is possibleif the object the pointer points to is of the base type:no dynamic bindingif the object is of a derived type:dynamic binding is possible• If the function called
· is redefined in the appropriate derived class and· has the same name and signature as
the (virtual) function in the base class,
Apply dynamic binding implemented through virtual functions
A virtual function is a member function of the base class thatcan be redefined at run-time
Even if the object is accessed by a base pointervirtual functions allow derived classesto replace the implementation of a function provided by thebase class at run time
A virtual function is a member function of the base class thatcan be redefined at run-time
Even if the object is accessed by a base pointervirtual functions allow derived classesto replace the implementation of a function provided by thebase class at run time
The replacement is always called whenever the object inquestion is of the derived class(even if the object is accessed by a base pointer)
This allows algorithms in the base class to be replaced in thederived class, even if users don’t know about the derivedclass
Shape ∗ppoly1 = &r e c t ; / / two po in te r s to ob jec ts o f base c lass ShapeShape ∗ppoly2 = & t r g l ; / / They are assigned the addresses of/ / der ived classes r e c t and t r g l ( v a l i d ?)/ / ==> we can only r e f e r the members t h a t/ / Rectangle and Tr iang le i n h e r i t from Shape
ppoly1−>set ( 4 , 5 ) ; / / can use ppoly1 ;ppoly2−>set ( 4 , 5 ) ;
cout << r e c t . area ( ) << endl ; / / cannot use ppoly1 ; Output 20cout << t r g l . area ( ) << endl ; / / cannot use ppoly2 ; Output 10
To make it possible for the pointers to the base class toaccess a member, we have to declared it in the base class
But what is the area of an undefined shape?
To access a (virtual) member of a base class we must declareit as virtual so that the use of pointers to base objects can befully applied to derived objects
class Shape {protected :i n t width , he igh t ;public :
void set ( i n t a , i n t b ) { width=a ; he igh t=b ; }/ / se t ( ) not v i r t u a l : i t does the same f o r a l l c lassesv i r t u a l i n t area ( void ) / / area ( ) as v i r t u a l f u n c t i o n/ / Does not make much sense here , but we need i t l a t e r{ return ( 0 ) ; } / / v i r t u a l : works s p e c i f i c i n der ived c l s .
} ;
class Rectangle : public Shape {public :
i n t area ( void ) { return ( width ∗ he igh t ) ; }} ;
/ / dynamic b ind ing :/ / At run−t ime the implementat ion o f the v i r t u a l f u n c t i o n/ / i s replaced by t h a t o f the der ived c lasscout << ppoly1−>area ( ) << endl ; / / ou tput : 20cout << ppoly2−>area ( ) << endl ; / / ou tput : 10cout << ppoly3−>area ( ) << endl ; / / ou tput : 0/ / desp i te v i r t u a l i t y we can dec lare an ob jec t o f type Shape/ / and to c a l l i t s area ( ) f u n c t i o n
Non-virtual member functions are resolved staticallyit is selected at compile-time based on the type of the pointerto the object
Virtual member functions are resolved dynamicallyit is selected at run-time based on the type of the object (notthe type of the pointer to that object)
Dynamic binding creates extra space and time overhead but...
class Student {f r iend ostream& operator <<(ostream&, Student &) ;public :
Student ( char∗ pF , char∗ pL ) ;~Student ( ) ;
protected : char∗ f i r s t ; char∗ l a s t ;} ;
class COEN244 : public Student {public :COEN244( char∗ pF , char∗ pL ) ;~COEN244( ) { count−−; }void setGrade ( f loa t , f loa t , f loa t , f l o a t ) ;f l o a t grade ( ) ; / / <===s t a t i c i n t getCount ( ) { return count ; }
private :f l o a t assignment ; f l o a t quiz ; f l o a t midterm ; f l o a t f i n a l ;s t a t i c i n t count ;
class ELEC311 : public Student {public :ELEC311( char∗ pF , char∗ pL ) ;~ELEC311 ( ) { count−−; }void setGrade ( f loa t , f loa t , f loa t , f l o a t ) ;f l o a t grade ( ) ; / / <===s t a t i c i n t getCount ( ) { return count ; }
private :f l o a t assignment ; f l o a t l a b o r a t o r y ; f l o a t midterm ; f l o a t f i n a l ;s t a t i c i n t count ;
class ELEC490 : public Student {public :ELEC490( char∗ pF , char∗ pL ) ;~ELEC490 ( ) { count−−; }void setGrade ( f l o a t ) ;f l o a t grade ( ) ; / / <===s t a t i c i n t getCount ( ) { return count ; }
private :f l o a t p r o j e c t ;s t a t i c i n t count ;
void main {COEN244 c1 ( " Jane " , "Doe" ) ;c1 . setGrade (50 , 55 , 25 , 95 ) ;p r i n t I n f o (&c1 ) ;
}
void p r i n t I n f o ( const Student∗ pStud ) {/ / Output name v ia stream i n s e r t i o n over loadcout << ∗pStud << endl ; / / QUESTION??? How do I know what k ind/ / o f Student pStud i s ?cout << pStud−>grade ( ) ; / / We cannot do t h i s ! ! !
class Student {f r iend ostream& operator <<(ostream&, Student &) ;public :
Student ( char∗ pF , char∗ pL ) ;~Student ( ) ;v i r t u a l f l o a t grade ( ) ; / / <===
protected : char∗ f i r s t ; char∗ l a s t ;} ;
class COEN244 : public Student {public :COEN244( char∗ pF , char∗ pL ) ;~COEN244( ) { count−−; }void setGrade ( f loa t , f loa t , f loa t , f l o a t ) ;v i r t u a l f l o a t grade ( ) ; / / <===s t a t i c i n t getCount ( ) { return count ; }
private :f l o a t assignment ; f l o a t quiz ; f l o a t midterm ; f l o a t f i n a l ;s t a t i c i n t count ;
void void main {COEN244 c1 ( " Jane " , "Doe" ) ;c1 . setGrade (50 , 55 , 25 , 95 ) ;p r i n t I n f o (&c1 ) ;
}
void p r i n t I n f o ( const Student∗ pStud ) {/ / Output name v ia stream i n s e r t i o n over loadcout << ∗pStud << endl ;cout << pStud−>grade ( ) ; / / grade ( ) o f COEN244 c lass w i l l be c a l l e d
When a base class member function is declared virtual,it permits run-time (dynamic) selection ofthe equivalent member function of the appropriate derivedclass
When a base class member function is declared virtual,it permits run-time (dynamic) selection ofthe equivalent member function of the appropriate derivedclass
Base class virtual functions may have their own definitionIt will be called
if the referenced object is a base class object orif the referenced derived class did not define anequivalent member function
Derived classes defining a virtual function need not beexplicitly declared virtual
Polymorphic behavior works with pointers & references ofbase classes
If using public inheritance,many base class member functions should be declared virtualto ensure that the derived class customizations will overridethe base class behavioreven in a context where a base class object is expected
A class should have a virtual destructor unless that class hasNO virtual functions
If we have any virtual functions, then we will probably going toprocess derived objects via a base pointer
Such processing may include invoking a destructor (normallydone implicitly via delete)
Recall virtual functions bind to the code associated with theclass of the object, rather than with the class of thepointer/reference
When you say delete basePtr, and the base class has a virtualdestructor, the destructor that gets invoked is the oneassociated with the type of the object *basePtr, rather thanthe one associated with the type of the pointer
class Employee {public :Employee ( const char ∗ , const char ∗ ) ;~Employee ( ) ; / / d e s t r u c t o r rec la ims memoryconst char ∗getFirstName ( ) const ;const char ∗getLastName ( ) const
/ / Pure v i r t u a l f u n c t i o n makes Employee abs t rac t base c lassv i r t u a l double earnings ( ) const = 0; / / pure v i r t u a lv i r t u a l void p r i n t ( ) const ; / / v i r t u a l
class Boss : public Employee {public :Boss ( const char ∗ , const char ∗ , double = 0 . 0 ) ;void setWeeklySalary ( double ) ;v i r t u a l double earnings ( ) const ;v i r t u a l void p r i n t ( ) const ;
SalaryWorker ( const char ∗ , const char ∗ , double = 0 . 0 ) ;void se tSa la ry ( double ) ;v i r t u a l double earnings ( ) const ;v i r t u a l void p r i n t ( ) const ;
HourlyWorker ( const char ∗ , const char ∗ , double = 0.0 , double = 0 . 0 ) ;void setWage ( double ) ;void setHours ( double ) ;v i r t u a l double earnings ( ) const ;v i r t u a l void p r i n t ( ) const ;
private :double wage ; / / wage per hourdouble hours ; / / hours worked f o r week
class CommissionWorker : public Employee {public :
CommissionWorker ( const char ∗ , const char ∗ , double = 0.0 , i n t = 0 ) ;void setCommission ( double ) ;void se tQuan t i t y ( i n t ) ;v i r t u a l double earnings ( ) const ;v i r t u a l void p r i n t ( ) const ;
protected :double commission ; / / amount per i tem soldi n t q u a n t i t y ; / / t o t a l i tems sold f o r week
l i s t [ 0 ] = &b ;l i s t [ 1 ] = &c1 ;l i s t [ 2 ] = &c2 ;l i s t [ 3 ] = &s1 ;l i s t [ 4 ] = &s2 ;l i s t [ 5 ] = &h1 ;l i s t [ 6 ] = &h2 ;l i s t [ 7 ] = &h3 ;
for ( i n t i = 0 ; i < 8 ; i ++) {l i s t [ i ]−> p r i n t ( ) ; / / using po in te r scout << " earned $ " << (∗ l i s t [ i ] ) . earn ings ( ) ; / / using ob jec ts
/ / S t a t i c Bindingcout << "STATIC BINDING" << endl ;
/ / access through ob jec ts : no polymorphism / v i r t u a l i t yb . p r i n t ( ) ; cout << " earned $ " << b . earn ings ( ) ;c1 . p r i n t ( ) ; cout << " earned $ " << c1 . earn ings ( ) ;c2 . p r i n t ( ) ; cout << " earned $ " << c2 . earn ings ( ) ;s1 . p r i n t ( ) ; cout << " earned $ " << s1 . earn ings ( ) ;s2 . p r i n t ( ) ; cout << " earned $ " << s2 . earn ings ( ) ;
h1 . p r i n t ( ) ; cout << " earned $ " << h1 . earn ings ( ) ;h2 . p r i n t ( ) ; cout << " earned $ " << h2 . earn ings ( ) ;h3 . p r i n t ( ) ; cout << " earned $ " << h3 . earn ings ( ) ;
/ / L i s t i n g 15.5 Heterogeneous l i s t processing using v i r t u a l f u n c t i o n sclass Person {
protected :char i d [ 1 0 ] ; / / data common to both typeschar∗ name ; / / v a r i a b l e leng th
public :Person ( const char i d [ ] , const char nm [ ] ) / / Kind type{ s t r cpy ( Person : : id , i d ) ; / / copy i d
name = new char [ s t r l e n (nm) + 1 ] ; / / get space f o r namei f (name == 0) { cout << " Out o f memory \ n " ; e x i t ( 0 ) ; }s t r cpy (name,nm) ; / / copy name
}
v i r t u a l void w r i t e ( ) const / / to d i sp lay data{ } / / not much to do at the moment
~Person ( ) / / r e t u r n heap memory{ delete [ ] name ; } / / f o r Person ob jec t on ly
class Student : public Person {private :char∗ major ; / / f o r s tudent on ly
public :Student ( const char i d [ ] , const char nm[ ] , const char m[ ] ): Person ( id ,nm) / / i n i t i a l i z a t i o n l i s t{ major = new char [ s t r l e n (m) + 1 ] ;
i f ( major == 0) { cout << " Out o f memory \ n " ; e x i t ( 0 ) ; }s t r cpy ( major ,m) ;
}void w r i t e ( ) const / / d i sp lay record
{ cout << " i d : " << i d << endl ; / / p r i n t id , namecout << " name : " << name << endl ;cout << " major : " << major <<endl <<endl ; / / s tudent on ly
}~Student ( ) { delete [ ] major ; } / / r e t u r n heap memory
void read ( i f s t r eam& f , Person∗& person ) { / / read one recordchar k ind [ 8 ] , i d [ 1 0 ] , name[ 8 0 ] , buf [ 8 0 ] ;f . g e t l i n e ( kind , 8 0 ) ; / / recognize the incoming typef . g e t l i n e ( id , 1 0 ) ; / / read i df . g e t l i n e (name, 8 0 ) ; / / read namef . g e t l i n e ( buf , 8 0 ) ; / / rank or major?i f ( strcmp ( kind , "FACULTY" ) == 0){ person = new Facu l ty ( id , name, buf ) ; } / / ob jec t i s Facu l ty
else i f ( strcmp ( kind , "STUDENT" ) == 0){ person = new Student ( id , name, buf ) ; } / / ob jec t i s Student
else{ cout << " Corrupted data : unknown type \ n " ; e x i t ( 0 ) ; }
}
void w r i t e ( const Person∗ p ) / / d i sp lay record{ p−>w r i t e ( ) ; } / / Facu l ty or Student?
/ / Test ingcout << endl << endl ;Person∗ data [ 2 0 ] ; i n t cnt = 0 ; / / a r ray o f po in te r s
i f s t r eam from ( " un iv . dat " ) ; / / i npu t data f i l ei f ( ! from ) { cout << " Cannot open f i l e \ n " ; return 0; }while ( ! from . eof ( ) )
{ read ( from , data [ cn t ] ) ; / / read u n t i l eofcnt ++; }
cout << " To ta l records read : " << cnt << endl << endl ;
for ( i n t i =0; i < cnt ; i ++){ w r i t e ( data [ i ] ) ; } / / d i sp lay data
for ( i n t j =0; j < cnt ; j ++){ delete data [ j ] ; } / / de le te the record