Upload
others
View
7
Download
0
Embed Size (px)
Citation preview
Part 6: From Java to C++
Inheritance
Prof. Dr. Ulrik Schroeder C++ - Einführung ins Programmieren
WS 03/04
http://learntech.rwth-aachen.de/lehre/ws04/c++/folien/index.html
e Learning
RW
TH
01.04.15 oo programming with C++ 2
public class Student {
int key; int matrikelnr; boolean male; String vorname, nachname;
Inheritance (Java example) public class Angestellter {
String stellung; int key; boolean male; String vorname, nachname;
public String toString () { String anrede; if (male) anrede = "Herr "; else anrede = "Frau ";
return anrede + vorname + " " + nachname; } ...}
public String toString () { String anrede; if (male) anrede = "Herr "; else anrede = "Frau ";
return anrede + vorname + " " + nachname; } ...}
e Learning
RW
TH
01.04.15 oo programming with C++ 3
public class Student {
int key; int matrikelnr; boolean male; String vorname, nachname;
Inheritance (Java example) public class Angestellter {
String stellung; int key; boolean male; String vorname, nachname;
public String toString () { String anrede; if (male) anrede = "Herr "; else anrede = "Frau ";
return anrede + vorname + " " + nachname; } ...}
public String toString () { String anrede; if (male) anrede = "Herr "; else anrede = "Frau ";
return anrede + vorname + " " + nachname; } ...}
public class Person { int key; boolean male; String vorname, nachname; ...}
e Learning
RW
TH
01.04.15 oo programming with C++ 4
public class Student extends Person {
int matrikelnr;
Inheritance (Java example) public class Angestellter extends Person {
String stellung;
public String toString () { String anrede; if (male) anrede = "Herr "; else anrede = "Frau ";
return anrede + vorname + " " + nachname; } ...}
public String toString () { String anrede; if (male) anrede = "Herr "; else anrede = "Frau ";
return anrede + vorname + " " + nachname; } ...}
public class Person { int key; boolean male; String vorname, nachname; ...}
public String toString () { String anrede; if (male) anrede = "Herr "; else anrede = "Frau ";
return anrede + vorname + " " + nachname; }
e Learning
RW
TH
01.04.15 oo programming with C++ 5
public class Student extends Person {
int matrikelnr; ...}
Inheritance (Java example) public class Angestellter extends Person {
String stellung; ...}
public class Person { int key; boolean male; String vorname, nachname; ...}
public String toString () { String anrede; if (male) anrede = "Herr "; else anrede = "Frau ";
return anrede + vorname + " " + nachname; }
e Learning
RW
TH
01.04.15 oo programming with C++ 6
s = p;
System.out.println (s.key + ", " + s.matrikelnr); System.out.println (p.key + ", " + p.matrikelnr);
s = a;
Student s = new Student (); Angestellter a = new Angestellter (); Person p;
Implicit Up Cast
implizite Datentypanpassung
Verboten!
Verboten! Verboten!
explizite Datentypanpassung
p = s;
s = (Student) p;
if (p instanceof Student) s = (Student) p;
e Learning
RW
TH
01.04.15 oo programming with C++ 7
Objects in class hierarchies
Person p = new Person (); Student s = new Student (); p = s; System.out.println (s.key + ", " + s.matrikelnr); System.out.println (p.key + ", " + p.matrikelnr); s = (Student) p;
p
s
Objekt Person
toString Attribute int key String vorname String nachname boolean male
Methode
Objekt Person
toString Attribute int key String vorname String nachname boolean male
Methode
Objekt Student Attribut int matrikelnr
e Learning
RW
TH
01.04.15 oo programming with C++ 8
Objects in class hierarchies
Person p = new Person (); Student s = new Student (); … p = s; System.out.println (s.key + ", " + s.matrikelnr); System.out.println (p.key + ", " + p.matrikelnr);
p
s
Objekt Person
toString Attribute int key String vorname String nachname boolean male
Methode
Objekt Person
toString Attribute int key String vorname String nachname boolean male
Methode
Objekt Student Attribut int matrikelnr
object itself still holds attribute matrikelnr !!!
System.out.println (p.key + ", " + ( (Student)p ).matrikelnr);
e Learning
RW
TH
01.04.15 oo programming with C++ 9
Class hierarchy in C++
class Person { ... }; // class Person
class Student : Person { ... }; inherit
public
int main( ) {
Student s(42, "Prefect", "Ford", false, 123456); };
Person p = s;
cout << s;
cout << p;
return 0;
} // main( )
ostream& operator << ( ostream& o, Person& p ) { if ( p.female ) o<<"Ms. "; else o<<"Mr. ";
o << p.pre << " " << p.name << " (key: " << p.key << ").";
return o << endl;
}
friend use
Mr. Ford Prefect (key: 42).
exactly the same in C++ except for syntax
e Learning
RW
TH
01.04.15 oo programming with C++ 10
Overloding operator << for Student
class Student : public Person { public:
Student( int k=0, string n=NULL, string p=NULL, bool f=true, int m=111111 ) : Person(k, n, p, f), matnr(m) { }; Student( Student& s ) : Person( s ) { matnr=s.matnr; } // ~Student( ) { } // nothing more to do than Person friend ostream& operator << ( ostream&, Student& );
protected: int matnr;
}; // class Student : Person ostream& operator << ( ostream& o, Student& p ) {
// o << (Person&)(*p) << " - MatNr: " << p.matnr << ")."; -- not using this one o << "Student " << p.pre << " " << p.name << " - MatNr: " << p.matnr; return o<<endl;
}
constructor of base class executed before this
use friend of base class
e Learning
RW
TH
01.04.15 oo programming with C++ 11
int main( ) {
Student s(42, "Prefect", "Ford", false, 123456); };
Person p = s;
cout << s;
cout << p;
return 0;
} // main( )
Mr. Ford Prefect (key: 42).
Student Ford Prefect – MatNr: 123456
e Learning
RW
TH
01.04.15 oo programming with C++ 12
Polymorph variables
y Greek expression for "various shapes" y data structure of "similar objects"
y traditionally: each object contains a tag field y switch statement to determine, which is the current object
y OO: each object brings its own, special method
for ( int i = 0; i < allObjects; i++ ) {
personList[ i ].display( );
} // for each object
each person object can be displayed
all objects bring their implementation how to be displayed
e Learning
RW
TH
01.04.15 oo programming with C++ 13
Redefinition of methods
void base::f( ) {
cout << "base.f( )" << endl;
} // base::f( )
polymorph (dynamic binding): each object has its own specific implementation of feature f( ).
void child::f( ) {
cout << "child.f( )" << endl;
} // child::f( )
class base { ... }; // class base
class child : base { ... };
class grandchild : public child { ... };
inherit public
unchanged visibility
void grandchild::f( ) {
cout << "grandchild.f( )" << endl;
} // grandchild::f( )
heirs inherit all non-private attributes and methods of
their base class
e Learning
RW
TH
01.04.15 oo programming with C++ 14
Polymorph variables
base
child
grand
polymorph variables can reference different objects (of the same class hierarchy)
static type can be more general than the dynamic type (of current content).
int main( ) { base b, *bptr; child c, *cptr; grandchild g, *gptr;
bptr = & b; bptr = & c; bptr = & g; cptr = & b; cptr = & c; cptr = & g; gptr = & b; gptr = & c; gptr = & g;
} // main
which usage is correct & why ? ?
holding the contract
e Learning
RW
TH
01.04.15 oo programming with C++ 15
Dynamic binding of methods
base
child
grand
must be explicitly defined in the base class
int main( ) { base *bptr; child c; grandchild g;
bptr = & c; bptr -> f( ); bptr = & g; bptr -> f( );
} // main
is only possible with pointer or references !
e Learning
RW
TH
01.04.15 oo programming with C++ 16
Virtual functions
class base {
public:
void f( );
}; // class base
class grandchild : public child {
public:
// redefinition
void f( );
}; // class grandchild
class child : public base {
public:
// redefinition
void f( );
}; // class child
must have identical signature for redefinition
are automatically virtual
virtual
e Learning
RW
TH
01.04.15 oo programming with C++ 17
Virtual functions
y declaration in base class must be virtual y each redefinition (same signature !!) is automatically virtual y dispatching during runtime: each object brings its own method
y Problem y programmer of base class must decide, which functions might be
redefined and should then be bound dynamically y normally redefinition will take place in future (while adapting the program
to new requirements, ...) => programmer must be clairvoyant
y Compared to Java y dynamic binding is standard y programmer needs not decide (in advance)
e Learning
RW
TH
01.04.15 oo programming with C++ 18
Example for dynamic binding
y Hierarchy of job positions y staff y employee y manager
y each earn money
staff
salary( )
employee manager
... some difference in how much though class staff { public:
staff( char* n ) : name( n ) { }; virtual int salary( ); char* getName( );
protected: char* name;
}; // class staff
#include "staff.h"
int staff::salary( ) { return 500; // Euro base salary
} // salary( )
char* staff::getName( ) { return name;
} // getName( ) can be redefined and used polymorphic
e Learning
RW
TH
01.04.15 oo programming with C++ 19
Redefinition of salary( )
class employee : public staff {
public:
employee( char* n, int wage ) : staff( n ), standardWage( wage ) { };
int salary( ); // redefine salary – automatically virtual
protected:
int standardWage;
}; // class employee
int employee::salary( ) {
return staff::salary( ) + standardWage;
} // salary( )
calls constructor of base class to initialize its part
use inherited method in redefined one.
e Learning
RW
TH
01.04.15 oo programming with C++ 20
Further redefinition of salary( )
class manager : public employee {
public:
manager( char* n, int wage, int grat )
: employee( n , wage ), gratification( grat ) { };
int salary( ); // redefine salary - virtual
protected:
int gratification;
}; // class manager
int manager::salary( ) {
return employee::salary( ) + gratification;
} // salary( )
constructor chaining
e Learning
RW
TH
01.04.15 oo programming with C++ 21
Dynamic binding of salary( )
int main( ) {
staff *s[ 3 ]; // static type staff; dynamic: staff, employee, manager
s[ 0 ] = new staff( "Stefan F" );
s[ 1 ] = new employee( "Emporio L", 2200 );
s[ 2 ] = new manager( "Michelle G", 2200, 1700 );
// ...
for ( int i = 0; i < s.length( ); i++ )
cout << s[ i ]->getName( ) << " salary: " << s[ i ]->salary( ) << endl;
} // main
polymorphic array s[ .. ]: static staff* can hold staff, employee, manager
static bound: getName, dynamic bound: salary( )
can getName be redefined? What's the difference?
e Learning
RW
TH
01.04.15 oo programming with C++ 22
friend functions are not inherited
y … but can utilize on polymorphic calls class staff { public: ...
friend ostream & operator << ( ostream &, staff & ); char* getName( );
... }; // class staff
ostream& operator << ( ostream& o, staff& s ) { return o << s.name << "has salary: " << s.salary( );
}
Can now be called on any object of class hierarchy, and needs not be redefined, as long as the same information will be printed.
e Learning
RW
TH
01.04.15 oo programming with C++ 23
Overload operator << in base class staff { public: ...
friend ostream & operator << ( ostream &, staff & ); virtual string toString( ) { char[7] s; sprintf(s,"%d", salary( ) ); return name+" salary: "+s; };
... }; // class staff
ostream& operator << ( ostream& o, staff& s ) { return o << s.toString( ); }
class employee : public staff { public: ...
virtual string toString( ) { char[7] s; sprintf(s,"%d", standardWage); return staff::toString( )+"+wage: "+s; };
}; // class employee different information can be displayed
e Learning
RW
TH
01.04.15 oo programming with C++ 24
int main( ) {
staff *s[ 3 ]; // dynamic: staff, employee, manager
// ...
for ( int i = 0; i < s.length( ); i++ ) {
( (manager *) s[ i ] ).grantGratification( 2000 );
} // for
} // main
unsafe static cast (C type) => no runtime check
Class casts y Up casts are safe and implicit
y all heirs fullfill at least the contract of their base classes and only might add additional features
y Down Casts are sometimes necessary, but unsafe y e.g. treating specific objects from a container
int main( ) {
staff *s[ 3 ]; // dynamic: staff, employee, manager
// ... automatic Up Cast for heteregeneous filling
for ( int i = 0; i < sizeof( s ) / sizeof( staff* ); i++ ) {
manager * m = dynamic_cast< manager *>( s[ i ] );
if ( m != NULL ) m.grantGratification( 2000 );
} // for
} // main results in NULL pointer, if not convertible to manager*
e Learning
RW
TH
01.04.15 oo programming with C++ 25
Abstract Classes, Interfaces
y C++: classes with pure virtual methods y like Java: abstract classes or interfaces specify behavior of heirs
class Printable { // sth which can be printed by ostream op<<
public:
virtual string toString( ) =0 ;
friend ostream& operator<<( ostream&, Printable& );
}; // interface Printable
ostream& operator<<( ostream& o, Printable& x) { return o << x.toString( );
} can be used for implementing methods
virtual method will be defined by heirs and dynamically bound for output
of course we don't know what to print yet!
e Learning
RW
TH
01.04.15 oo programming with C++ 26
Polymorphic methods & late binding
#include "printable.h" class staff : public Printable {
// … virtual string toString( ) { char s[7]; sprintf( s, "%d", salary( ) ); return name+" has salary "+s; } // … no friend ostream& op <<( … declaration
} // class staff
class employee : public staff { public:
employee( char* n="who?", int w=0 ) : staff( n ), wage( w ) { }; int salary( ){ return staff::salary( ) + wage; };
protected: int wage;
} // class employee
only define toString( )
cout << staff is now defined
not even redefine toString( )
e Learning
RW
TH
01.04.15 oo programming with C++ 27
Polymorphic methods & late binding
int main( ) { // fill heteregeneous array staff* s[5]; // pointer for late binding, no default objects s[0] = new staff( "Flat Staff" ); s[1] = new employee( "Emp Lo Yee", 1200 ); s[2] = new manager( "Man A. Ger", 200, 1900 ); s[3] = new staff( *s[2] ); // degrade manager to staff
// use homogeneously for ( unsigned int i=0; i < sizeof( s )/sizeof( staff* ); i++ ) cout << s[ i ] << endl;
} // main
? which of the assignments work?
what will cout print for the array elements?
e Learning
RW
TH
01.04.15 oo programming with C++ 28
object model with virtual method table
Printable
op <<( Printable& )
virtual toString( )=0
abstract class, can not be instantiated
employee
salary( )
is a
staff
virtual salary( )
toString( )
is a
main uses
uses
uses
implicit up_cast: Printable&
… o << x.toString( );
virtual in Printable dynamic bound from employee
… sprintf( s, "%d", salary( ) ); return name+" has salary "+s;
… inherited from staff
dynamic bound from employee
return staff::salary( ) + wage;
… cout << s[ i ] << endl;
Emp Lo Yee has salary 1700
computed: 500+1200
employee object salary( )
toString( ) base
wage
staff object salary( )
toString( )
base
e Learning
RW
TH
01.04.15 oo programming with C++ 29
Overloading inherited methods
y different signature except co-variant specialization
class manager : public employee { public:
// overloading toString( ) string toString( string pre ) { return pre + employee::toString( ); }
… } // class manager
… manager* m = dynamic_cast< manager * >( s[2] ); if ( m != NULL )
cout << m->toString( "I am the boss: " );
e Learning
RW
TH
01.04.15 oo programming with C++ 30
multiple inheritance (mix-in)
y inherit code from more than one class y idea: Tree<t> could inherit from Linkable<t> and LinkedList<t>
'A'
'y' 'x' 'z'
't' 'v' 'u' 's'
first next
Tree<char>
count = 2
e Learning
RW
TH
01.04.15 oo programming with C++ 31
? Multiple Inheritance (Mix-In) ?
y geometric shapes geom. Object
colored Square
fill() color()
...
area() circumference() ...
needs operations from both !
Problems of multiple inheritance (Java Design Team): error prone disputable whether necessary at all how to handle multiply inherited features ?
move()
colored Object Square
e Learning
RW
TH
01.04.15 oo programming with C++ 32
Ambiguity of inherited features
y repeated inheritance y differently redefined methods y name conflicts? y attributes (twice or once?)
f: not redefined, always the same, but once or three times?
g or g’ ? h, h’ or h’’
which i ?
B
f( ), g’( ), h’( ), i( )
C
f( ), g( ), h’’( ) , i( )
D
f( ), g( ), h( ), i( )
A
f( ), g( ), h( )
e Learning
RW
TH
01.04.15 oo programming with C++ 33
C++ : virtual inheritance
Pkw Transporter
Kombi
Kfz class Pkw : public Kfz { … additional Pkw defs … }
class Transporter : public Kfz {
… additional Transporter defs … }
class Kombi : public Pkw, public Transporter {
… additional Kombi defs …
} has all properties of Kfz twice!!
main( ) { …
Kombi* k = new Kombi(…);
k->getKfzNr( ); ambigious call
k->Pkw::getKfzNr( );
scope operator to decide
e Learning
RW
TH
01.04.15 oo programming with C++ 34
C++ : virtual inheritance
Pkw Transporter
Kombi
Kfz class Pkw : virtual public Kfz { … additional Pkw defs … }
class Transporter : virtual public Kfz {
… additional Transporter defs … }
class Kombi : public Pkw, public Transporter {
… additional Kombi defs …
} has all properties of Kfz only once!!
main( ) { …
Kombi* k = new Kombi(…);
k->getKfzNr( ); this is ok
same general design problem:
we must know in advance, that some developer might multiply inherit our class in future ???
e Learning
RW
TH
01.04.15 oo programming with C++ 35
Inheritance y class derived : public base { … additional features … }
y transitive class relation y heir inherits all non-private members (attributes and methods)
y polymorphic use y each heir fullfills the contract of its ancestors y a program name of static type "base" can thus hold an object of a more
specialized class "derived" y dynamic binding
y each object brings its own and correct method y C++: if it is declared virtual in the base and used as a pointer or reference
y abstract classes and interfaces y specification of methods to be implemented by heirs y most powerful tool of object-oriented programming
y multiple inheritance y should not be used for inheriting attributes, and better no code (only interfaces
as realized in Java)