C++ Programmierkurs - ZAIK

Transcrição

C++ Programmierkurs - ZAIK
1
C++ Programmierkurs
3
6. Vererbung und Polymorphismus
Wintersemester 04 / 05
6.1
6.2
6.3
6.4
6.5
Christian Hagemeier
Lehrstuhl Prof. Dr. Schrader
Institut für Informatik
Universität zu Köln
Einführung in Vererbung
Vererbung in C++
Grundlagen des Polymorphismus
Abstrakte Klassen
Virtuelle Destruktoren
mittwochs 17–18:30 Uhr
Hörsaal II der Physikalischen Institute
http://www.zaik.de/AFS/teachings/
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
2
4
Gliederung der Vorlesung
6.1 Einführung in Vererbung
20.10.: Organisatorisches und Einführung
27.10.: Einführung und Kontrollstrukturen
03.11.: Kontrollstrukturen
10.11.: Kontrollstrukturen und Funktionen
17.11.: Funktionen
24.11.: Vektoren, Zeiger
01.12.: Zeiger, Strings
08.12.: Klassen (1)
15.12.: Klassen (2), Überladen von Operatoren
22.12.: Vererbung und Polymorphismus
12.01.: Datei und Stream Ein–/Ausgabe, Diverses
• Wiederverwendbarkeit
• Erzeugen einer Klasse aus existierender Basisklasse
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
– "erbt" Daten und Verhalten der Basisklasse
– "Verfeinerung" mit weiteren Details
• stärker spezialisierte Gruppe an Objekten wird
abgebildet
• Verhalten der Ursprungsklasse kann modifiziert
werden
• Vererbung über mehrere Stufen möglich (indirekte
Vererbung)
• Mehrfachvererbung möglich (Vererbung von
mehreren Basisklassen)
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
1
5
Beziehungen im Objektmodell
7
Vererbungshierarchie: Beispiel 1
• Abstraktion
CommunityMember
– zielt auf Gemeinsamkeiten der Klassen im Modell
• "ist ein"-Beziehung
– wird im Objektmodell durch Vererbung abgebildet
– Objekte der abgeleiteten Klasse können als Objekte der
Basisklasse betrachtet werden
– Beispiel Husky ist ein Hund: Huskies besitzen alle
Eigenschaften eines Hundes
Employee
Faculty
Student
Staff
Alumnus
Single
inheritance
Single
inheritance
• "hat ein"-Beziehung
– Komposition: Klassenattribut von diesem Typ
– Objekt enthält ein oder mehrere Objekte anderer Klassen als
Variablen
– Beispiel Hund hat einen Kopf
Programmierkurs C++ – WS 04/05
Teacher
Single
inheritance
AdministratorTeacher
Multiple
inheritance
Administrator
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
6
Basisklasse und abgeleitete Klasse
8
Vererbungshierarchie: Beispiel 2
• Basisklasse spiegelt typischerweise größere
Objektmenge wieder als abgeleitete Klasse
• Beispiele:
Basisklasse
Student
Shape
Loan
Employee
Account
Programmierkurs C++ – WS 04/05
abgeleitete Klassen
GraduateStudent
UndergraduateStudent
Circle
Triangle
Rectangle
CarLoan
HomeImprovementLoan
MortgageLoan
FacultyMember
StaffMember
CheckingAccount
SavingsAccount
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Shape
TwoDimensionalShape
Circle
Square
Programmierkurs C++ – WS 04/05
Triangle
ThreeDimensionalShape
Sphere
Cube
Tetrahedron
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
2
9
11
6.2 Vererbung in C++
Zugriffssteuerung protected
• 3 Arten der Vererbung:
• Zwischenstufe zwischen public und private
• Zugriff auf protected Klassenmitglieder
– public
• Jedes Objekt der abgeleiteten Klasse ist auch Objekt der
Basisklasse
• Objekte der Basisklasse sind keine Objekte der abgeleiteten Kl.
• Beispiel: Alle Huskies sind Hunde, nicht alle Hunde sind
Huskies
• Nichtprivate Elemente der Basisklasse können verwendet
werden (durch vererbte nicht-private Methoden)
– wie bei private und protected:
• durch Basisklassenmethoden
• durch friend-Funktionen der Basisklasse
– Schärfer als public, laxer als private:
• durch Methoden der abgeleiteten Klasse
• durch friend-Funktionen der abgeleiteten Klasse
– private
• Zugriff nicht möglich von externen Klassen
• Nutzung der public- und protected-Methoden
von Basisklassen: einfach Methodenname
verwenden!
• Alternative zu Komposition (siehe "hat ein"-Beziehung)
– protected
• selten genutzt
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
10
12
public-Vererbung
Aufteilung des Quellcodes auf Dateien (1)
• Syntax:
• Headerdateien
class TwoDimensionalShape : public Shape
– Klasse TwoDimensionalShape erbt von Klasse Shape
• private Elemente der Basisklasse:
– sind nicht direkt verfügbar
– werden trotzdem mit vererbt (Zugriff über entsprechende
Methoden)
• public- und protected-Methoden und -Variablen
werden so "übernommen"
• friend-Funktionen werden nicht vererbt
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
– Deklarationen von globalen Variablen
– Prototypen von Funktionen
– Deklaration von Klassen mit Methodenprototypen
• Implementationsdateien
– Implementation der Funktionen und Klassen
• Insgesamt eine main()-Funktion in allen Implementationsdateien
• Problem: Sicherstellen, daß jede Deklaration nur einmal
vorgenommen wird
• Lösung: Präprozessoranweisungen
– #ifndef <marke>: wenn <marke> nicht definiert ist, binde
folgenden Code ein, sonst überspringe ihn
– #define <marke>: definiert <marke>
– #endif: Gegenstück zu vorangegangenen #ifndef
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
3
13
15
Aufteilung des Quellcodes auf Dateien (2)
Beispiel "Punkt": Implementationsdatei (1)
• Genereller Aufbau:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#ifndef _test_h_
#define _test_h_
// hier kommt der Quellcode mit den
// Deklarationen hin
#endif
• Einbinden der Deklaration vor Nutzung/Definition
mittels #include "dateiname"
• Vorgehen beim Kompilieren
– Jede Implementationsdatei wird vom Compiler separat in
Objektcode übersetzt
– Diese Objektcode-Dateien werden vom Linker zum
ausführbaren Programm zusammengebunden
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
// Fig. 9.13: point2.cpp
// Point2 class member-function definitions.
#include <iostream>
using std::cout;
#include "point2.h"
// Point2 class definition
// default constructor
Point2::Point2( int xValue, int yValue )
{
x = xValue;
y = yValue;
} // end Point2 constructor
// set x in coordinate pair
void Point2::setX( int xValue )
{
x = xValue; // no need for validation
} // end function setX
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
14
16
Beispiel "Punkt": (Headerdatei)
Beispiel "Punkt": Implementationsdatei (2)
1
2
3
4
5
6
8
9
10
11
12
13
14
15
16
17
18
19
20
21
23
24
25
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// Fig. 9.12: point2.h
// Point2 class definition represents an x-y coordinate pair.
#ifndef POINT2_H
#define POINT2_H
class Point2 {
public:
Point2( int = 0, int = 0 ); // default constructor
void setX( int );
int getX() const;
// set x in coordinate pair
// return x from coordinate pair
void setY( int );
int getY() const;
// set y in coordinate pair
// return y from coordinate pair
void print() const;
// output Point2 object
protected:
int x; // x part of coordinate pair
int y; // y part of coordinate pair
}; // end class Point2
// return x from coordinate pair
int Point2::getX() const
{
return x;
} // end function getX
// set y in coordinate pair
void Point2::setY( int yValue )
{
y = yValue; // no need for validation
} // end function setY
// return y from coordinate pair
int Point2::getY() const
{
return y;
} // end function getY
#endif
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
4
17
19
Beispiel "Punkt": Implementationsdatei (3)
Beispiel "Kreis": Implementationsdatei (1)
45
46
47
48
49
50
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// output Point2 object
void Point2::print() const
{
cout << '[' << x << ", " << y << ']';
} // end function print
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
// Fig. 9.15: circle3.cpp
// Circle3 class member-function definitions.
#include <iostream>
using std::cout;
#include "circle3.h"
// Circle3 class definition
// default constructor
Circle3::Circle3( int xValue, int yValue, double radiusValue )
{
x = xValue;
y = yValue;
setRadius( radiusValue );
} // end Circle3 constructor
// set radius
void Circle3::setRadius( double radiusValue )
{
radius = ( radiusValue < 0.0 ? 0.0 : radiusValue );
} // end function setRadius
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
18
Beispiel "Kreis": Headerdatei
1
// Fig. 9.14: circle3.h
2
// Circle3 class contains x-y coordinate pair and radius.
3
#ifndef CIRCLE3_H
4
#define CIRCLE3_H
5
6
#include "point2.h" // Point2 class definition
7
8
class Circle3 : public Point2 {
10 public:
12
// default constructor
13
Circle3( int = 0, int = 0, double = 0.0 );
14
15
void setRadius( double );
// set radius
16
double getRadius() const;
// return radius
17
18
double getDiameter() const;
// return diameter
19
double getCircumference() const; // return circumference
20
double getArea() const;
// return area
21
22
void print() const;
// output Circle3 object
24 private:
25
double radius; // Circle3's radius
27 }; // end class Circle3
29 #endif
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
20
Beispiel "Kreis": Implementationsdatei (2)
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// return radius
double Circle3::getRadius() const
{
return radius;
} // end function getRadius
// calculate and return diameter
double Circle3::getDiameter() const
{
return 2 * radius;
} // end function getDiameter
// calculate and return circumference
double Circle3::getCircumference() const
{
return 3.14159 * getDiameter();
} // end function getCircumference
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
5
21
Beispiel "Kreis": Implementationsdatei (3)
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
24
circle.setX( 2 );
// set new x-coordinate
25
circle.setY( 2 );
// set new y-coordinate
26
circle.setRadius( 4.25 ); // set new radius
27
28
// display new point value
29
cout << "\n\nThe new location and radius of circle are\n";
30
circle.print();
31
32
// display floating-point values with 2 digits of precision
33
cout << fixed << setprecision( 2 );
34
35
// display Circle3's diameter
36
cout << "\nDiameter is " << circle.getDiameter();
37
38
// display Circle3's circumference
39
cout << "\nCircumference is " << circle.getCircumference();
40
41
// display Circle3's area
42
cout << "\nArea is " << circle.getArea();
43
44
cout << endl;
45
46
return 0; // indicates successful termination
48 } // end main
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
22
24
// calculate and return area
double Circle3::getArea() const
{
return 3.14159 * radius * radius;
} // end function getArea
// output Circle3 object
void Circle3::print() const
{
cout << "Center = [" << x << ", " << y << ']'
<< "; Radius = " << radius;
} // end function print
Programmierkurs C++ – WS 04/05
23
Beispiel: main()-Funktion (2)
Beispiel: main()-Funktion (1)
Ausgabe des Beispiels
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Fig. 9.16: circletest3.cpp
// Testing class Circle3.
#include <iostream>
X coordinate is 37
Y coordinate is 43
Radius is 2.5
using std::cout;
using std::endl;
using std::fixed;
The new location and radius of circle are
Center = [2, 2]; Radius = 4.25
Diameter is 8.50
Circumference is 26.70
Area is 56.74
#include <iomanip>
using std::setprecision;
#include "circle3.h"
// Circle3 class definition
int main()
{
Circle3 circle( 37, 43, 2.5 ); // instantiate Circle3 object
// display point coordinates
cout << "X coordinate is " << circle.getX()
<< "\nY coordinate is " << circle.getY()
<< "\nRadius is " << circle.getRadius();
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
6
25
27
Verwendung von protected
6.3 Grundlagen des Polymorphismus
• Vorteile:
• Polymorphismus: Auswahl der auszuführenden Aktion wird
dynamisch durch Klasse bestimmt
– abgeleitete Klassen können Werte direkt modifizieren
– etwas schneller (Vermeidung der Verwendung von get-/setFunktionen)
• Kernkonzept: Abgeleitete Klassen können als Instanzen der
Basisklasse behandelt werden
• Nachteile:
– Zulässigkeitstest innerhalb der Basisklasse wird umgangen
• Dadurch: Nahtloses Einfügen neuer Funktionalität/ Klassen in
existierendes Modell möglich
• abgeleitete Klasse kann illegale Werte zuweisen
– Implementationsabhängigkeit
– Neue Klasse können problemlos hinzugefügt werden und werden
automatisch wie bisherige Klassen berücksichtigt
• Methoden der abgeleiteten Klasse sind meist abhängiger von
der Implementation der Basisklasse
• Modifikation der Basisklasse kann konsequenzen auf
abgeleitete Klasse haben (fragile Software)
• Aufruf einer Methode, die in abgeleiteter Klasse überladen
wurde:
– Bisher: Auswahl der ausgeführten Funktion anhand des Typs
– Jetzt: Auswahl der Funktion dynamisch anhand der Instanz
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
26
28
Konstruktoren, Destruktoren, Zuweisung
Methodenzugriff über Zeiger
• Instantiierung der Objekte mittels geschachtelter
Konstruktorenaufrufe (Basiskonstruktor nach
abgeleitetem Konstruktor)
• Aufruf der Destruktoren in umgekehrter Reihenfolge
• Konstruktoren, Destruktor und Zuweisungsoperator
werden nicht vererbt
• Wiederholung: Zeiger müssen im Allgemeinen genau
von dem Typ sein, auf dessen Objekt sie zeigen
– Aber: Konstruktoren und Zuweisungsoperator der
abgeleiteten Klasse können die der Basisklasse aufrufen
– Sonst: Syntaxfehler
• Daher bisher möglich:
– Basisklassenzeiger auf Basisklasseninstanz
– Zeiger der abgeleiteten Klasse auf entsprechende Instanz
• Jetzt neu: Basisklassenzeiger auf Instanz der
abgeleiteten Klasse
– Objekt wird als ein Objekt der Basisklasse interpretiert!
– Es werden auf die Daten des abgeleiteten Objekts die
Methoden der Basisklasse angewendet
– Methodenaufruf hängt von Zeigertyp und nicht von Objekttyp
ab!
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
7
29
Beispiel: Zeigerzugriff auf abgeleitete Klasse
Virtuelle Methoden
• Bisher: Zeigertyp bestimmt Methodenaufruf
class Point { // ... };
class Circle : public Point { // ... };
Point p; Circle c;
• Neu: virtual-Methoden
Point* pPtr = &p;
Circle* cPtr = &c;
pPtr->print(); // print() von Point auf Point-Instanz
cPtr->print(); // print() von Circle auf Circle-Instanz
pPtr = &c;
pPtr->print();
– Instanz (und NICHT Zeigertyp) bestimmt aufgerufene
Methode!
• Wozu ist das nötig?
– Betrachte Klassen Circle, Triangle, Rectangle, alle
von Shape abgeleitet
// kein Syntaxfehler, da Circle von Point
// abgeleitet!
// print() von Point auf Circle-Instanz
• jede besitzt eigene Methode draw()
– um beliebige Form zu zeichnen:
• Zeiger der Basisklasse Shape ruft der Reihe nach alle drawMethoden auf
• Programm ermittelt richtige Zeichenfunktion zur Laufzeit
(dynamisch)
• So können alle Formen gleich behandelt werden
• Circle-Instanz wird als Point interpretiert!
• Auswahl der Methode findet entsprechend anhand
des Variablentyps (hier: Zeigertyps) statt
• Resultiert aus "Ist ein"-Beziehung zwischen Klassen
Programmierkurs C++ – WS 04/05
31
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
30
32
Zeigerzugriff mit Basisklassenzeiger
Virtuelle Methoden in C++
• Es können alle Funktionen der Basisklasse auf dieser
Instanz verwendet werden
• Zur Verwendung virtueller Methoden in C++ muß
Schlüsselwort virtual bei Methode draw
angegeben werden
• draw muß in jeder abgeleiteten Klasse überladen
werden (Methode muß gleiche Signatur besitzten!)
– Aufruf genau wie bei Basisklassen-Instanzen
– Diese arbeiten auf den Daten der Instanz der abgeleiteten
Klasse
• Methoden oder Variablen der abgeleiteten Klasse
können nicht verwendet werden!
– Zugriff darauf liefert Syntaxfehler, da sie nicht in Basisklasse
definiert sind
• Bis hier hin: Alles aus Vererbung bekannt!
– Beispiel: virtual void draw() const;
• virtuelle Methoden bleiben in allen abgeleiteten
Klassen virtuell
– Trotzdem sollte man es wegen der Klarheit in jeder Klasse
dazuschreiben
• Dynamische Bindung:
– wähle korrekte Methode zur Laufzeit
– findet ausnahmslos mit Zeigern statt!
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
8
33
35
Beispiel "Kreis" mit virtueller Funktion (1)
Beispiel "Kreis": Testprogramm (1)
1
2
3
4
5
6
8
9
10
11
12
13
14
15
16
17
18
19
20
21
23
24
25
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Fig. 10.8: point.h
// Point class definition represents an x-y coordinate pair.
#ifndef POINT_H
#define POINT_H
class Point {
public:
Point( int = 0, int = 0 ); // default constructor
void setX( int );
int getX() const;
// set x in coordinate pair
// return x from coordinate pair
void setY( int );
int getY() const;
Print als virtual deklariert.
set y in coordinate pair
Wird in alle abgeleiteten
return y from coordinate pair
Klassen virtual sein.
//
//
virtual void print() const;
// output Point object
private:
int x; // x part of coordinate pair
int y; // y part of coordinate pair
}; // end class Point
#endif
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
// Fig. 10.10: fig10_10.cpp
// Introducing polymorphism, virtual functions and dynamic
// binding.
#include <iostream>
using std::cout;
using std::endl;
using std::fixed;
#include <iomanip>
using std::setprecision;
#include "point.h"
#include "circle.h"
// Point class definition
// Circle class definition
int main()
{
Point point( 30, 50 );
Point *pointPtr = 0;
Circle circle( 120, 89, 2.7 );
Circle *circlePtr = 0;
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
34
Beispiel "Kreis": Headerdatei (2)
1
// Fig. 10.9: circle.h
2
// Circle class contains x-y coordinate pair and radius.
3
#ifndef CIRCLE_H
4
#define CIRCLE_H
6
#include "point.h" // Point class definition
7
8
class Circle : public Point {
10 public:
11
12
// default constructor
13
Circle( int = 0, int = 0, double = 0.0 );
14
15
void setRadius( double );
// set radius
16
double getRadius() const;
// return radius
17
18
double getDiameter() const;
// return diameter
19
double getCircumference() const; // return circumference
20
double getArea() const;
// return area
21
22
virtual void print() const;
// output Circle object
24 private:
25
double radius; // Circle's radius
27 }; // end class Circle
29 #endif
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
36
Beispiel "Kreis": Testprogramm (2)
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// set floating-point numeric formatting
cout << fixed << setprecision( 2 );
// output objects point and circle using static binding
cout << "Invoking print function on point and circle "
<< "\nobjects with static binding "
<< "\n\nPoint: ";
point.print();
// static binding
cout << "\nCircle: ";
circle.print();
// static binding
// output objects point and circle using dynamic binding
cout << "\n\nInvoking print function on point and circle "
<< "\nobjects with dynamic binding";
// aim base-class pointer at base-class object and print
pointPtr = &point;
cout << "\n\nCalling virtual function print with base-class"
<< "\npointer to base-class object"
<< "\ninvokes base-class print function:\n";
pointPtr->print();
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
9
37
39
Beispiel "Kreis": Testprogramm (3)
Zusammenfassung virtuelle Methoden
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
• stellen Polymorphismus zur Verfügung
// aim derived-class pointer at derived-class
// object and print
circlePtr = &circle;
cout << "\n\nCalling virtual function print with "
<< "\nderived-class pointer to derived-class object "
<< "\ninvokes derived-class print function:\n";
circlePtr->print();
– Gleiche "Mitteilung", hier draw, wird vielen verschiedenen
Objekten gegeben
• alles durch Basiszeiger
– Mitteilung nimmt viele verschiedene Formen an
• Basiszeiger auf Basisobjekt, Zeiger von abgeleiteter
Klasse auf abgeleitete Klasse:
// aim base-class pointer at derived-class object and print
pointPtr = &circle;
cout << "\n\nCalling virtual function print with base-class"
<< "\npointer to derived-class object "
<< "\ninvokes derived-class print function:\n";
pointPtr->print(); // polymorphism: invokes circle's print
cout << endl;
return 0;
} // end main
– klar!
• Basiszeiger auf abgeleitetes Objekt:
– Es können nur Methoden der Basisklasse benutzt werden
• Zeiger von abgeleiteter Klasse auf Basisklasse:
Zur Laufzeit wird ermittelt,
daß pointPtr auf ein
Circle Objekt zeigt und die
print-Funktion von Circle
wird aufgerufen.
Dies ist ein Beispiel für
Polymorphismus!
Programmierkurs C++ – WS 04/05
– Syntaxfehler
• Programme sind leichter erweiterbar, da "neue"
Klassen mit "alten" gleich behandelt werden
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
38
40
Beispiel "Kreis": Programmausgabe
6.4 Abstrakte Klassen
Invoking print function on point and circle
objects with static binding
• Abstrakte Klassen
– einziger Zweck: eine Basisklasse zu sein!
– sind unvollständig
Point: [30, 50]
Circle: Center = [120, 89]; Radius = 2.70
• abgeleitete Klassen füllen Lücken
Invoking print function on point and circle
objects with dynamic binding
– Es können keine Objekte von diesen Klassen erzeugt
werden
– ABER: Es können Zeiger und Referenzen von diesem Typ
benutzt werden!
Calling virtual function print with base-class
pointer to base-class object
invokes base-class print function:
[30, 50]
• Konkrete Klassen
Calling virtual function print with
derived-class pointer to derived-class object
invokes derived-class print function:
Center = [120, 89]; Radius = 2.70
– Objekte können davon erzeugt werden
– implementieren alle Funktionen, die deklariert werden
Calling virtual function print with base-class
pointer to derived-class object
invokes derived-class print function:
Center = [120, 89]; Radius = 2.70
Programmierkurs C++ – WS 04/05
• Abstrakte Klassen sind nicht notwendig, aber nützlich
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
10
41
43
Abstrakte Klassen in C++
6.5 Virtuelle Destruktoren
• Benötigen mindestens eine rein virtuelle Methode
– Deklaration rein virtueller Methoden:
virtual void draw() const =
= 0;
0;
• Problem: Was passiert, wenn ein Objekt mit delete
zerstört wird, auf das über einen Basiszeiger
zugegriffen wird?
– besitzen Implementationen
– können überladen werden
• Einfache Lösung:
• Reguläre (=nicht reine) virtuelle Methoden
– deklariere Destruktor als virtuell!
– Dadurch werden alle Destruktoren von abgeleiteten Klassen
virtuell und es wird immer der richtige ausgewählt
– Regel: sobald mindestens eine Methode virtuell ist, sollte
auch ein virtueller (evtl. leerer) Destruktor erzeugt werden!
• Rein virtuelle Methoden
– besitzen keine Implementation
– müssen überladen werden!
• Abstrakte Klassen können auch Daten und konkrete
Methoden besitzen (eine Methode muß jedoch rein
virtuell sein)
• Zeiger auf abstrakte Basisklassen
• Konstruktoren können nicht virtuell sein. Wieso nicht?
– sinnvoll für Polymorphismus
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
42
Beispiel für abstrakte Basisklasse
• Abstrakte Klasse Shape
– Definiert draw als rein virtuelle Methode
• Circle, Triangle, Rectangle sind von Shape als
konkrete Klassen abgeleitet:
– Jede muß Methode draw überladen
• Bildschirmmanager weiß, daß jedes Objekt sich
selbst zeichnen kann
Programmierkurs C++ – WS 04/05
Christian Hagemeier – Lehrstuhl Prof. Dr. Schrader
11

Documentos relacionados