Blatt 4

Werbung
Konzepte der Programmiersprachen
Sommersemester 2010
4. Übungsblatt
Besprechung am 9. Juli 2010
http://www.iste.uni-stuttgart.de/ps/Lehre/SS2010/V_Konzepte/
Aufgabe 4.1: Klassen in C++
Das folgende C++-Programm berechnet Primzahlen. Nach welchem Algorithmus funktioniert dieses Programm? Beschreiben Sie die verwendete Klassenhierarchie. Welche
Regeln gibt es in C++ den Zugriff auf die Komponenten einer Klasse?
# i n c l u d e <iostream >
c l a s s Knoten {
public :
Knoten ∗ Eingabe ;
Knoten ( Knoten ∗ s ) { Eingabe = s ; }
v i r t u a l i n t Ausgabewert ( ) { r e t u r n 0 ; }
};
c l a s s Generator : p u b l i c Knoten {
i n t Wert ;
public :
i n t Ausgabewert ( void ) { r e t u r n Wert ++; }
Generator ( i n t S t a r t w e r t ) : Knoten ( 0 ) { Wert = S t a r t w e r t ; }
};
c l a s s F i l t e r : p u b l i c Knoten {
i n t Faktor ;
public :
i n t Ausgabewert ( ) ;
F i l t e r ( Knoten ∗ s , i n t f ) : Knoten ( s ) { F a k t o r = f ; }
};
i n t F i l t e r : : Ausgabewert ( ) {
int n;
do {
n = Eingabe−>Ausgabewert ( ) ;
} while ( ! ( n % F a k t o r ) ) ;
return n ;
}
i n t main ( void ) {
Generator C ( 2 ) ;
Knoten ∗ S i e b = &C ;
i n t Primzahl , max ;
1
s t d : : cout << "Primzahl-Sieb in C++\n\nWieviele Primzahlen? " ;
s t d : : c i n >> max ;
f o r ( i n t i = 0 ; i < max ; i ++) {
Primzahl = Sieb −>Ausgabewert ( ) ;
s t d : : cout << Primzahl << ’ ’ ;
S i e b = new F i l t e r ( Sieb , Primzahl ) ;
}
s t d : : cout << "\n" ;
return 0 ;
}
Aufgabe 4.2: Abstrakte Datentypen
Vergleichen Sie die Möglichkeiten des Verbergens von privaten Eigenschaften eines
Typs in Java und Ada.
• Welche Möglichkeiten bietet Ada?
• Welche Möglichkeiten bietet Java?
• Welche Unterschiede ergeben sich für den Programmierer? Wie können voneinander abhängige Deklarationen auf Dateien/Pakete aufgeteilt werden? Fördern
diese Möglichkeiten das Verständnis des Programm-Entwurfs?
• In Ada 95 dürfen Pakete nicht zyklisch voneinander abhängen, welche Entscheidungen macht dies für den Entwurf von abstrakten Datentypen notwendig?
• In Ada 2005 werden limited with clauses eingeführt, die nur eine incomplete
view der darin deklarierten Typen sichtbar machen, auf diese Weise jedoch zyklische Paket-Abhängigkeiten ermöglichen. Dadurch entstehen zusätzliche Freiheiten, welche?
Aufgabe 4.3: Vererbung, Varianz
In der objektorientierten Programmierung gibt es die Begriffe der Kovarianz, Invarianz
und Kontravarianz der Signaturen von Methoden.
1. Charakterisieren Sie mit einigen Sätzen jeden dieser Begriffe.
2. Welche Zusammenhänge gibt es mit der Präfix- und der Parameternotation für
Methodenaufrufe?
3. Welche Vor- und Nachteile hat Kovarianz für ererbte Methodenimplementierungen?
2
Aufgabe 4.4: Wertesemantik und lokale Variablen
In einer Programmiersprache sei folgende Semantik gegeben:
• Es gibt Klassen, die Unterklassen besitzen können. Unterklassen können gegenüber ihren Oberklassen zusätzliche Datenattribute und Operationen besitzen.
• In Unterprogrammen sind lokale Variablen zugelassen, deren deklarierter Typ
eine Klasse ist. Klassen sind auch als deklarierter Typ von globalen Variablen und
Parametern sowie Funktionsresultaten erlaubt.
• Die Zuweisung hat Wertesemantik. Den obigen Variablen können Instanzen einer
beliebigen Unterklasse zugewiesen werden, wobei alle Datenattribute der Unterklasse erhalten bleiben.
Daraus ergeben sich allerdings einige Probleme.
1. Welches Implementierungsproblem tritt bei der Realisierung solcher lokaler Variablen auf? Wie kann es ohne Änderung der Sprachsemantik gelöst werden? Gibt
es unvermeidbare Nachteile?
2. Können die Schwierigkeiten aus der vorigen Teilaufgabe durch Änderung der
Sprachsemantik vermieden werden, ohne dabei die „typischen“ Charakteristika
objektorientierter Sprachen zu verlieren?
Aufgabe 4.5: Namensbindung
Gegeben sind folgende Deklarationen und Definitionen in der objektorientierten Programmiersprache X++:
class C is
method M is begin ... end;
method M1 (P : integer) is begin ... end;
method M2 is begin ... end;
end C;
class C1 inherits C is
method M (P : integer) is begin ... end;
method M1 (P : integer) is begin ... end;
method M2 return integer is begin ... end;
end C1;
class C2 inherits C is
method M is begin ... end;
method M1 is begin ... end;
method M3 (P : integer) is begin ... end;
3
end C2;
class C12 inherits C1 is
method M2 is begin ... end;
method M3 (P : integer) is begin ... end;
end C12;
1. Welche Notation erwarten Sie für den Aufruf einer Methode in der Sprache X++?
Wäre die andere Notation auch möglich? Wenn ja, was bedeuten dann die Methoden?
2. Nehmen Sie an, die Sprache benutze für Methodenaufrufe Präfix-Notation (also
O.M() anstatt M(O)). Diskutieren Sie, welche Zuweisungen und Methodenaufrufe unter welchen Umständen legal sind und welche Methode tatsächlich aufgerufen wird.
OC : C;
OC12 : C12;
OC := OC12;
OC.M3(1);
OC.M1(1);
x : integer := OC.M2;
3. Welche Methoden werden in welcher Klasse redefiniert? Für welche Methoden
erwarten Sie eine Überladung? Warum?
4. Welches weitere Problem kann es in diesem Zusammenhang mit der Parameterliste einer Methode noch geben? Hinweis: Versuchen Sie zu klären, was der folgende Code bedeutet.
class A;
class B inherits A;
class C is
method M1 (P : A);
method M2 (P : B);
method M3 (P : C);
end;
class D inherits C
method M1 (P : B);
method M2 (P : A);
method M3 (P : D);
end;
4
Aufgabe 4.6: Implementierung der dynamischen Bindung
In dieser Aufgabe soll die Implementierung von Vererbung und dynamischer Bindung
von Methoden veranschaulicht werden. Empfinden Sie die Klassenhierarchie aus dem
folgenden kurzen C++ Programm in reinem C (ohne C++-Erweiterungen) oder einer
anderen Sprache nach. Beachten Sie die Hinweise von Folie 7-23 des Skripts. DispatchVektoren können als Arrays von Funktionszeigern dargestellt werden.
# i n c l u d e < s t d i o . h>
class A
{
public :
v i r t u a l void printname ( )
{
p r i n t f ( "Klasse: A\n" ) ;
}
};
c l a s s B : public A
{
public :
v i r t u a l void printname ( )
{
p r i n t f ( "Redefinition in: B\n" ) ;
}
};
c l a s s C : public A
{
public :
v i r t u a l void printname ( )
{
p r i n t f ( "Redefinition in: C\nAufruf an Original:\n" ) ;
A : : printname ( ) ;
p r i n t f ( "Zurueck in C.\n" ) ;
}
};
i n t main ( i n t argc , char ∗ argv [ ] )
{
f o r ( i n t i = 0 ; i < a r g c ; ++ i ) {
s w i tc h ( argv [ i ] [ 0 ] ) {
c a s e ’A’ : (new A)−>printname ( ) ; break ;
c a s e ’B’ : (new B)−>printname ( ) ; break ;
c a s e ’C’ : (new C)−>printname ( ) ; break ;
}
}
}
5
Herunterladen