part 6: from java to c++ inheritanceseppke/... · e learning 01.04.15 oo programming with c++ 4...

35
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

Upload: others

Post on 27-May-2020

7 views

Category:

Documents


0 download

TRANSCRIPT

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)