vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Tag D

Anworten und Lösungen

Tag 1

Quiz

  1. Was ist der Unterschied zwischen einem Interpreter und einem Compiler?
  1. Wie kompilieren Sie den Quellcode mit Ihrem Compiler?
  1. Welche Aufgabe obliegt dem Linker?
  1. Wie lauten die Schritte in einem normalen Entwicklungszyklus?

Übungen

  1. Das Programm initialisiert zwei Integer-Variablen und gibt dann deren Summe und Produkt aus.
  2. Schauen Sie ins Handbuch Ihres Compilers.
  3. Sie müssen vor include (erste Zeile des Programms) das Zeichen # stellen.
  4. Das Programm gibt die Worte Hello World auf den Bildschirm aus, gefolgt von einem Zeilenumbruch.

Tag 2

Quiz

  1. Was ist der Unterschied zwischen einem Compiler und einem Präprozessor?
  1. Warum nimmt die main()-Funktion einen Sonderstatus ein?
  1. Wie sehen die zwei Möglichkeiten zur Kommentierung aus, und worin unterscheiden sie sich?
  1. Können Kommentare verschachtelt sein?
  1. Können Kommentare länger als eine Zeile sein?

Übungen

  1. Schreiben Sie ein Programm, daß »Ich liebe C++« auf dem Bildschirm ausgibt.
    1: #include <iostream.h>
    2:
    3: int main()
    4: {
    5: cout << "Ich liebe C++\n";
    6: return 0;
    7: }
  2. Schreiben Sie das kleinstmögliche Programm, das kompiliert, gelinkt und gestartet werden kann.
    int main() { return 0; }
  3. FEHLERSUCHE: Geben Sie das nachfolgende Programm ein und kompilieren Sie es. Warum funktioniert es nicht? Wie können Sie den Fehler beheben?
    1: #include <iostream.h>
    2: int main()
    3: {
    4: cout << Ist hier ein Fehler?";
    5: return 0;
    6: }
  1. Beseitigen Sie den Fehler in Übung 3, kompilieren und linken Sie das Programm neu und starten Sie es noch einmal.
    1: #include <iostream.h>
    2: int main()
    3: {
    4: cout << "Ist hier ein Fehler?";
    5: return 0;
    6: }

Tag 3

Quiz

  1. Was ist der Unterschied zwischen einer Integer-Variablen und einer Fließkomma-variablen?
  1. Welche Unterschiede bestehen zwischen einer Variablen vom Typ unsigned short int und einer Variablen vom Typ long int?
  1. Was sind die Vorteile einer symbolischen Konstanten verglichen mit einer literalen Konstanten?
  1. Was sind die Vorteile des Schlüsselwortes const verglichen zu #define?
  1. Wodurch zeichnen sich ein guter und ein schlechter Variablenname aus?
  1. Was ist der Wert von BLAU in dem folgenden Aufzählungstyp?
  1. Welche der folgenden Variablennamen sind gut, welche sind schlecht und welche sind ungültig?

Übungen

  1. Was wäre der korrekte Variablentyp, um die folgenden Informationen abzulegen?
  1. Erstellen Sie gute Variablennamen für diese Informationen.
  1. Deklarieren Sie eine Konstante für PI (Wert 3.14159)
  1. Deklarieren Sie eine Variable vom Typ float und initialisieren Sie sie mit Ihrer PI-Konstanten.

Tag 4

Quiz

  1. Was ist ein Ausdruck?
  1. Ist x = 5 + 7 ein Ausdruck? Was ist sein Wert?
  1. Was ist der Wert von 201 / 4?
  1. Was ist der Wert von 201 % 4?
  1. Wenn meinAlter, a und b Integer-Variablen sind, wie lauten Ihre Werte nach
    meinAlter = 39;
    a = meinAlter++;
    b = ++meinAlter;
    meinAlter: 41, a: 39, b: 41
  2. Was ist der Wert von 8 + 2 * 3?
  1. Was ist der Unterschied zwischen if(x = 3) und if(x == 3)?
  1. Ergeben die folgenden Werte true oder false?

a. 0

false

b. 1

true

c. -1

true

d. x = 0

false

e. x == 0 // angenommen x hat den Wert 0

true

Übungen

  1. Schreiben Sie eine einzige if-Anweisung, die zwei Integer-Variablen überprüft und die größere in die kleinere umwandelt. Verwenden Sie nur eine else-Klausel.
    if (x > y)
    x = y;
    else // y > x || y == x
    y = x;
  2. Überprüfen Sie das folgende Programm. Stellen Sie sich vor, sie geben drei Zahlen ein, und notieren Sie sich, was Sie als Ausgabe erwarten.
    1: #include <iostream.h>
    2: int main()
    3: {
    4: int a, b, c;
    5: cout << "Bitte drei Zahlen eingeben:\n";
    6: cout << "a: ";
    7: cin >> a;
    8: cout << "\nb: ";
    9: cin >> b;
    10: cout << "\nc: ";
    11: cin >> c;
    12:
    13: if (c = (a-b))
    14: {cout << "a: ";
    15: cout << a;
    16: cout << "minus b: ";
    17: cout << b;
    18: cout << "gleich c: ";
    19: cout << c << endl;}
    20: else
    21: cout << "a-b ist nicht gleich c: " << endl;
    22: return 0;
    23: }
  3. Geben Sie das Programm aus Übung 2 ein, kompilieren und linken Sie es und starten Sie es dann. Geben Sie die Zahlen 20, 10 und 50 ein. Hat die Ausgabe Ihren Erwartungen entsprochen? Wenn nein, warum nicht?
  1. Überprüfen Sie das folgende Programm und raten Sie, wie die Ausgabe lautet.
    1: #include <iostream.h>
    2: int main()
    3: {
    4: int a = 1, b = 1, c;
    5: if (c = (a-b))
    6: cout << "Der Wert von c ist: " << c;
    7: return 0;
    8: }
  2. Erfassen, kompilieren, linken und starten Sie das Programm aus Übung 4. Wie lautete die Ausgabe? Warum?

Tag 5

Quiz

  1. Welche Unterschiede bestehen zwischen dem Funktionsprototyp und der Funktionsdefinition?
  1. Müssen die Namen der Parameter in Prototyp, Definition und Aufruf der Funktion übereinstimmen?
  1. Wie wird eine Funktion deklariert, die keinen Wert zurückliefert?
  1. Wenn Sie keinen Rückgabewert deklarieren, von welchem Typ des Rückgabewertes wird dann ausgegangen?
  1. Was ist eine lokale Variable?
  1. Was ist ein Gültigkeitsbereich?
  1. Was ist Rekursion?
  1. Wann sollte man globale Variablen verwenden?
  1. Was versteht man unter dem Überladen von Funktionen?
  1. Was ist Polymorphie?

Übungen

  1. Setzen Sie den Prototypen für eine Funktion namens Perimeter() auf, die einen vorzeichenlosen Integer (unsigned long int) zurückgibt und zwei Parameter, beide vom Typ unsigned short int, übernimmt.
    unsigned long int Perimeter(unsigned short int, unsigned short int);
  2. Definieren Sie die Funktion Perimeter(), wie in Übung 1 beschrieben. Die zwei Parameter stellen die Länge und Breite eines Rechtecks dar. Die Funktion soll den Umfang (zweimal die Länge plus zweimal die Breite) zurückliefern.
    unsigned long int Perimeter(unsigned short int length, 
    unsigned short int width)
    {
    return 2*length + 2*width;
    }
  3. FEHLERSUCHE: Was ist falsch an der Funktion im folgenden Quellcode?
    #include <iostream.h>
    void myFunc(unsigned short int x);
    int main()
    {
    unsigned short int x, y;
    y = myFunc(int);
    cout << "x: " << x << " y: " << y << "\n";
    }

    void myFunc(unsigned short int x)
    {
    return (4*x);
    }
  1. FEHLERSUCHE: Was ist falsch an der Funktion im folgenden Quellcode?
    #include <iostream.h>
    int myFunc(unsigned short int x);
    int main()
    {
    unsigned short int x, y;
    y = myFunc(x);
    cout << "x: " << x << " y: " << y << "\n";
    }

    int myFunc(unsigned short int x);
    {
    return (4*x);
    }
  1. Schreiben Sie eine Funktion, die zwei Integer-Argumente vom Typ unsigned short übernimmt und das Ergebnis der Division des ersten Arguments durch das zweite Argument zurückliefert. Führen Sie die Division nicht durch, wenn die zweite Zahl Null ist, sondern geben Sie -1 zurück.
    short int Divider(unsigned short int valOne, unsigned short int valTwo)
    {
    if (valTwo == 0)
    return -1;
    else
    return valOne / valTwo;
    }
  2. Schreiben Sie ein Programm, das den Anwender zur Eingabe von zwei Zahlen auffordert und die Funktion aus Übung 5 aufruft. Geben Sie die Antwort aus oder eine Fehlermeldung, wenn das Ergebnis -1 lautet.
    #include <iostream.h>
    typedef unsigned short int USHORT;
    typedef unsigned long int ULONG;
    short int Divider(
    unsigned short int valone,
    unsigned short int valtwo);
    int main()
    {
    USHORT one, two;
    short int answer;
    cout << "Enter two numbers.\n Number one: ";
    cin >> one;
    cout << "Number two: ";
    cin >> two;
    answer = Divider(one, two);
    if (answer > -1)
    cout << "Answer: " << answer;
    else
    cout << "Error, can't divide by zero!";
    return 0;
    }
  3. Schreiben Sie ein Programm, das um die Eingabe einer Zahl und einer Potenz bittet. Schreiben Sie eine rekursive Funktion, um die Zahl zu potenzieren. Lautet beispielsweise die Zahl 2 und die Potenz 4 sollte die Funktion 16 zurückliefern.
    #include <iostream.h>
    typedef unsigned short USHORT;
    typedef unsigned long ULONG;
    ULONG GetPower(USHORT n, USHORT power);
    int main()
    {
    USHORT number, power;
    ULONG answer;
    cout << "Geben Sie eine Zahl ein: ";
    cin >> number;
    cout << "Zu welcher Potenz? ";
    cin >> power;
    answer = GetPower(number,power);
    cout << number << " hoch " << power << "ist gleich " <<
    answer << endl;
    return 0;
    }

    ULONG GetPower(USHORT n, USHORT power)
    {
    if(power == 1)
    return n;
    else
    return (n * GetPower(n,power-1));
    }

Tag 6

Quiz

  1. Was ist der Punktoperator und wozu wird er verwendet?
  1. Wann wird Speicher reserviert - bei der Deklaration oder bei der Definition?
  1. Ist die Deklaration einer Klasse deren Schnittstelle oder deren Implementierung?
  1. Was ist der Unterschied zwischen öffentlichen (public) und privaten (private) Datenelementen?
  1. Können Elementfunktionen privat sein?
  1. Können Datenelemente öffentlich sein?
  1. Wenn Sie zwei Cat-Objekte deklarieren, können diese unterschiedliche Werte in ihren itsAge-Datenelementen haben?
  1. Enden Klassendeklarationen mit einem Semikolon? Und die Definitionen von Klassenmethoden?
  1. Wie würde die Header-Datei für eine Cat-Funktion Meow() aussehen, die keine Parameter übernimmt und void zurückliefert?
    void Cat::Meow()
  2. Welche Funktion wird aufgerufen, um eine Klasse zu initialisieren?

Übungen

  1. Schreiben Sie einen Code, der eine Klasse namens Employee (Angestellter) mit folgenden Datenelementen deklariert: age, YearsOfService und Salary
    class Employee
    {
    int Age;
    int YearsOfService;
    int Salary;
    };
  2. Schreiben Sie die Klasse Employee neu, mit privaten Datenelementen und zusätzlichen öffentlichen Zugriffsmethoden, um jedes der Datenelemente zu lesen und zu setzen.
    class Employee
    {
    public:
    int GetAge() const;
    void SetAge(int age);
    int GetYearsOfService()const;
    void SetYearsOfService(int years);
    int GetSalary()const;
    void SetSalary(int salary);

    private:
    int Age;
    int YearsOfService;
    int Salary;
    };
  3. Schreiben Sie mit Hilfe der Employee-Klasse ein Programm, das zwei Angestellte erzeugt. Setzen Sie deren Alter (age), Beschäftigungszeitraum (YearsOfService) und Gehalt (Salary), und geben Sie diese Werte aus.
    int main()
    {
    Employee John;
    Employee Sally;
    John.SetAge(30);
    John.SetYearsOfService(5);
    John.SetSalary(50000);

    Sally.SetAge(32);
    Sally.SetYearsOfService(8);
    Sally.SetSalary(40000);

    cout << "John und Sally versehen bei AcmeSexist den gleichen Job\n";
    cout << "John ist " << John.GetAge() << " Jahre alt und seit ";
    cout << John.GetYearsOfService() << " Jahren in der Firma.\n";
    cout << "John verdient $" << John.GetSalary() << " im Jahr.\n\n";
    cout << "Sally ist " << Sally.GetAge() << " Jahre alt und seit ";
    cout << Sally.GetYearsOfService() << " Jahren in der Firma.\n";
    cout << "Sally verdient $" << Sally.GetSalary)= << " im Jahr.\n";
    cout << "Manchmal ist das Leben ungerecht\n";
    return 0;
    }
  4. Als Fortsetzung von Übung 3 nehmen Sie eine Methode in Employee auf, die berichtet, wieviel tausend Dollar der Angestellte verdient, aufgerundet auf die nächsten 1000 Dollar.
    float Employee:GetRoundedThousands()const
    {
    return (Salary+500) / 1000;
    }
  5. Ändern Sie die Klasse Employee so, daß Sie age, YearsOfService und Salary initialisieren können, wenn Sie einen neuen Angestellten anlegen.
    class Employee
    {
    public:

    Employee(int Age, int yearsOfService, int salary);
    int GetAge()const;
    void SetAge(int Age);
    int GetYearsOfService()const;
    void SetYearsOfService(int years);
    int GetSalary()const;
    void SetSalary(int salary);

    private:
    int Age;
    int YearsOfService;
    int Salary;
    };
  6. FEHLERSUCHE: Was ist falsch an der folgenden Deklaration?
    class Square
    {
    public:
    int Side;
    }
  1. FEHLERSUCHE: Warum ist die folgende Klassendeklaration nicht besonders nützlich?
    class Cat
    {
    int GetAge()const;
    private:
    int itsAge;
    };
  1. FEHLERSUCHE: Welche drei Fehler wird der Compiler in folgendem Code finden?
    class  TV
    {
    public:
    void SetStation(int Station);
    int GetStation() const;
    private:
    int itsStation;
    };
    int main()
    {
    TV myTV;
    myTV.itsStation = 9;
    TV.SetStation(10);
    TV myOtherTv(2);
    return 0;
    }

Tag 7

Quiz

  1. Wie initialisiert man mehr als eine Variable in einer for-Schleife?
  1. Warum sollte man goto vermeiden?
  1. Ist es möglich, eine for-Schleife zu schreiben, deren Rumpf niemals ausgeführt wird?
  1. Ist es möglich, while-Schleifen in for-Schleifen zu verschachteln?
  1. Ist es möglich, eine Schleife zu erzeugen, die niemals endet? Geben Sie ein Beispiel.
  1. Was passiert, wenn Sie eine Endlosschleife erzeugt haben?

Übungen

  1. Wie lautet der Wert von x, wenn die folgende for-Schleife durchlaufen ist?
    for (int x = 0; x < 100; x++)
  1. Schreiben Sie eine verschachtelte for-Schleife, die ein Muster von 10 x 10 Nullen (0) ausgibt.
    for (int i = 0; i< 10; i++)
    {
    for ( int j = 0; j< 10; j++)
    cout << "0";
    cout << "\n";
    }
  2. Schreiben Sie eine for-Anweisung, die in Zweierschritten von 100 bis 200 zählt.
    for (int x = 100; x<=200; x+=2)
  3. Schreiben Sie eine while-Schleife, die in Zweierschritten von 100 bis 200 zählt.
    int x = 100;
    while (x <= 200)
    x+= 2;
  4. Schreiben Sie eine do...while-Schleife, die in Zweierschritten von 100 bis 200 zählt.
    int x = 100;
    do
    {
    x+=2;
    } while (x <= 200);
  5. FEHLERSUCHE: Was ist falsch an folgendem Code?
    int counter = 0;
    while (counter < 10)
    {
    cout << "Zaehler: " << counter;
    }
  1. FEHLERSUCHE: Was ist falsch an folgendem Code?
    for (int counter = 0; counter < 10; counter++);
    cout << counter << " ";
  1. FEHLERSUCHE: Was ist falsch an folgendem Code?
    int counter = 100;
    while (counter < 10)
    {
    cout << "Zaehler: " << counter;
    counter--;
    }
  1. FEHLERSUCHE: Was ist falsch an folgendem Code?
    cout << "Geben Sie eine Zahl zwischen 0 und 5 ein: ";
    cin >> theNumber;
    switch (theNumber)
    {
    case 0:
    doZero();
    case 1: // Weiter mit naechstem case
    case 2: // Weiter mit naechstem case
    case 3: // Weiter mit naechstem case
    case 4: // Weiter mit naechstem case
    case 5:
    doOneToFive();
    break;
    default:
    doDefault();
    break;
    }

Tag 8

Quiz

  1. Mit welchem Operator bestimmt man die Adresse einer Variablen?
  1. Mit welchem Operator ermittelt man einen Wert, der an einer Adresse gespeichert ist, auf die ein Zeiger weist?
  1. Was ist ein Zeiger?
  1. Worin besteht der Unterschied zwischen der in einem Zeiger gespeicherten Adresse und dem Wert an dieser Adresse?
  1. Worin besteht der Unterschied zwischen dem Indirektionsoperator und dem Adreßoperator?
  1. Worin besteht der Unterschied zwischen const int * pEins und int * const pZwei?

Übungen

  1. Was bewirken die folgenden Deklarationen:
  1. Wie würden Sie einen Zeiger deklarieren, der auf eine Variable namens ihrAlter vom Typ unsigned short verweist?
    unsigned short *pAlter = &ihrAlter;
  2. Weisen Sie der Variable ihrAlter den Wert 50 zu. Verwenden Sie dazu den Zeiger, den Sie in Übung 2 deklariert haben.
    *pAlter = 50;
  3. Schreiben Sie ein kleines Programm, das einen Integer und einen Zeiger auf diesen Integer deklariert. Weisen Sie dem Zeiger die Adresse des Integers zu. Verwenden Sie den Zeiger, um der Integer-Variable einen Wert zuzuweisen.
    int derInteger;
    int *pInteger = &derInteger;
    *pInteger = 5;
  4. FEHLERSUCHE: Was ist falsch an folgendem Code?
    #include <iostream.h>
    int main()
    {
    int *pInt;
    *pInt = 9;
    cout << "Der Wert von pInt: " << *pInt;
    return 0;
    }
  1. FEHLERSUCHE: Was ist falsch an folgendem Code?
    int main()
    {
    int SomeVariable = 5;
    cout << "SomeVariable: " << SomeVariable << "\n";
    int *pVar = & SomeVariable;
    pVar = 9;
    cout << "SomeVariable: " << *pVar << "\n";
    return 0;
    }

Tag 9

Quiz

  1. Worin besteht der Unterschied zwischen einer Referenz und einem Zeiger?
  1. Wann sollte man statt einer Referenz lieber einen Zeiger verwenden?
  1. Was für einen Rückgabewert hat new, wenn nicht genug Speicher für Ihr new-Objekt vorhanden ist?
  1. Was ist eine konstante Referenz?
  1. Was ist der Unterschied zwischen Übergabe als Referenz und Übergabe einer Referenz?

Übungen

  1. Schreiben Sie ein Programm, das eine Variable vom Typ int, eine Referenz auf int und einen Zeiger auf int deklariert. Verwenden Sie den Zeiger und die Referenz, um den Wert in int zu manipulieren.
    int main()
    {
    int varOne;
    int& rVar = varOne;
    int* pVar = &varOne;
    rVar = 5;
    *pVar = 7;
    return 0;
    }
  2. Schreiben Sie ein Programm, das einen konstanten Zeiger auf einen konstanten Integer deklariert. Initialisieren Sie den Zeiger mit einer Integer-Variablen varOne. Weisen Sie varOne den Wert 6 zu. Weisen Sie mit Hilfe des Zeigers varOne den Wert 7 zu. Erzeugen Sie eine zweite Integer-Variable varTwo. Richten Sie den Zeiger auf die Variable varTwo. Kompilieren Sie diese Übung noch nicht.
    int main()
    {
    int varOne;
    const int * const pVar = &varOne;
    *pVar = 7;
    int varTwo;
    pVar = &varTwo;
    return 0;
    }
  3. Kompilieren Sie jetzt das Programm aus Übung 2. Welche Zeilen produzieren Fehler und welche Warnungen?
  1. Schreiben Sie ein Programm, das einen vagabundierenden Zeiger erzeugt.
    int main()
    {
    int * pVar;
    *pVar = 9;
    return 0;
    }
  2. Beheben Sie den Fehler im Programm aus Übung 4.
    int main()
    {
    int VarOne;
    int * pVar = &varOne;
    *pVar = 9;
    return 0;
    }
  3. Schreiben Sie ein Programm, das eine Speicherlücke erzeugt.
    #include <iostream.h>

    int * FuncOne();
    int main()
    {
    int * pInt = FuncOne();
    cout << "Wert von pInt nach Rueckkehr in main: " << *pInt << endl;
    return 0;
    }

    int * FuncOne()
    {
    int * pInt = new int (5);
    cout << "Wert von pInt in FuncOne: " << *pInt << endl;
    return pInt;
    }
  4. Beheben Sie den Fehler im Programm aus Übung 6.
    #include <iostream.h>

    int FuncOne();
    int main()
    {
    int theInt = FuncOne();
    cout << "Wert von pInt nach Rueckkehr in main: " << theInt << endl;
    return 0;
    }

    int FuncOne()
    {
    int * pInt = new int (5);
    cout << "Wert von pInt in FuncOne: " << *pInt << endl;
    delete pInt;
    return temp;
    }
  5. FEHLERSUCHE: Was ist falsch an diesem Programm?
    1:     #include <iostream.h>
    2:
    3: class CAT
    4: {
    5: public:
    6: CAT(int age) { itsAge = age; }
    7: ~CAT(){}
    8: int GetAge() const { return itsAge;}
    9: private:
    10: int itsAge;
    11: };
    12:
    13: CAT & MakeCat(int age);
    14: int main()
    15: {
    16: int age = 7;
    17: CAT Boots = MakeCat(age);
    18: cout << "Boots ist " << Boots.GetAge() << " Jahre alt\n";
    return 0;
    19: }
    20:
    21: CAT & MakeCat(int age)
    22: {
    23: CAT * pCat = new CAT(age);
    24: return *pCat;
    25: }
  1. Beheben Sie den Fehler im Programm aus Übung 8.
    1:     #include <iostream.h>
    2:
    3: class CAT
    4: {
    5: public:
    6: CAT(int age) { itsAge = age; }
    7: ~CAT(){}
    8: int GetAge() const { return itsAge;}
    9: private:
    10: int itsAge;
    11: };
    12:
    13: CAT * MakeCat(int age);
    14: int main()
    15: {
    16: int age = 7;
    17: CAT * Boots = MakeCat(age);
    18: cout << "Boots ist " << Boots->GetAge() << " Jahre alt\n";
    19: delete Boots;
    20: return 0;
    21: }
    22:
    23: CAT * MakeCat(int age)
    24: {
    25: return new CAT(age);
    26: }

Tag 10

Quiz

  1. In welcher Hinsicht müssen sich überladene Elementfunktionen unterscheiden?
  1. Was ist der Unterschied zwischen einer Deklaration und einer Definition?
  1. Wann wird der Kopierkonstruktor aufgerufen?
  1. Wann wird der Destruktor aufgerufen?
  1. Wie unterscheidet sich der Kopierkonstruktor vom Zuweisungsoperator (=)?
  1. Was ist der this-Zeiger?
  1. Wie unterscheiden Sie zwischen dem Präfix- und Postfix-Inkrementoperator?
  1. Können Sie den +-Operator für Operanden vom Typ short überladen?
  1. Ist es in C++ erlaubt, den ++-Operator zu überladen, so daß er einen Wert Ihrer Klasse dekrementiert?
  1. Mit welchem Rückgabewert müssen Umwandlungsoperatoren deklariert werden?

Übungen

  1. Schreiben Sie eine Klassendeklaration SimpleCircle mit (nur) einer Elementvariablen: itsRadius. Sehen Sie einen Standardkonstruktor, einen Destruktor und Zugriffsmethoden für radius vor.
    class SimpleCircle
    {
    public:
    SimpleCircle();
    ~SimpleCircle();
    void SetRadius(int);
    int GetRadius();
    private:
    int itsRadius;
    };
  2. Aufbauend auf der Klasse aus Übung 1, setzen Sie die Implementierung des Standardkonstruktors auf und initialisieren Sie itsRadius mit dem Wert 5.
    SimpleCircle::SimpleCircle():
    itsRadius(5)
    {}
  3. Fügen Sie der Klasse einen zweiten Konstruktor hinzu, der einen Wert als Parameter übernimmt, und weisen Sie diesen Wert itsRadius zu.
    SimpleCircle::SimpleCircle(int radius):
    itsRadius(radius)
    {}
  4. Erzeugen Sie für Ihre SimpleCircle-Klasse einen Präfix- und einen Postfix-Inkrementoperator, die itsRadius inkrementieren.
    const SimpleCircle& SimpleCircle::operator++()
    {
    ++(itsRadius);
    return *this;
    }

    // Postfix-Operator ++(int).
    const SimpleCircle SimpleCircle::operator++ (int)
    {
    // lokales SimpleCircle-Objekt deklarieren und mit *this initialisieren
    SimpleCircle temp(*this);
    ++(itsRadius);
    return temp;
    }
  5. Ändern Sie SimpleCircle so, daß itsRadius auf dem Heap gespeichert wird, und passen Sie die bestehenden Methoden an.
    class SimpleCircle
    {
    public:
    SimpleCircle();
    SimpleCircle(int);
    ~SimpleCircle();
    void SetRadius(int);
    int GetRadius();
    const SimpleCircle& operator++();
    const SimpleCircle operator++(int);
    private:
    int *itsRadius;
    };


    SimpleCircle::SimpleCircle()
    {itsRadius = new int(5);}

    SimpleCircle::SimpleCircle(int radius)
    {itsRadius = new int(radius);}

    SimpleCircle::~SimpleCircle()
    {
    delete itsRadius;
    }

    const SimpleCircle& SimpleCircle::operator++()
    {
    ++(*itsRadius);
    return *this;
    }

    // Postfix-Operator ++(int).
    const SimpleCircle SimpleCircle::operator++ (int)
    {
    // lokales SimpleCircle-Objekt deklarieren und mit *this initialisieren
    SimpleCircle temp(*this);
    ++(*itsRadius);
    return temp;
    }
  6. Fügen Sie einen Kopierkonstruktor für SimpleCircle hinzu.
    SimpleCircle::SimpleCircle(const SimpleCircle & rhs)
    {
    int val = rhs.GetRadius();
    itsRadius = new int(val);
    }
  7. Fügen Sie einen Zuweisungsoperator für SimpleCircle hinzu.
    SimpleCircle& SimpleCircle::operator=(const SimpleCircle & rhs)
    {
    if (this == &rhs)
    return *this;
    delete itsRadius;
    itsRadius = new int;
    *itsRadius = rhs.GetRadius();
    return *this;
    }
  8. Schreiben Sie ein Programm, das zwei SimpleCircle-Objekte erzeugt. Verwenden Sie den Standardkonstruktor zur Erzeugung des einen Objekts, und instantiieren Sie das andere mit dem Wert 9. Wenden Sie den Inkrement-Operator auf beide Objekte an und geben Sie dann die Werte beider Objekte aus. Abschließend weisen Sie dem ersten Objekt das zweite zu und geben Sie nochmals die Werte beider Objekte aus.
    #include <iostream.h>

    class SimpleCircle
    {
    public:
    // Konstruktoren
    SimpleCircle();
    SimpleCircle(int);
    SimpleCircle(const SimpleCircle &);
    ~SimpleCircle() {}

    // Zugriffsfunktionen
    void SetRadius(int);
    int GetRadius()const;

    // Operatoren
    const SimpleCircle& operator++();
    const SimpleCircle operator++(int);
    SimpleCircle& operator=(const SimpleCircle &);

    private:
    int *itsRadius;
    };


    SimpleCircle::SimpleCircle()
    {itsRadius = new int(5);}

    SimpleCircle::SimpleCircle(int radius)
    {itsRadius = new int(radius);}

    SimpleCircle::SimpleCircle(const SimpleCircle & rhs)
    {
    int val = rhs.GetRadius();
    itsRadius = new int(val);
    }
    SimpleCircle::~SimpleCircle()
    {
    delete itsRadius;
    }
    SimpleCircle& SimpleCircle::operator=(const SimpleCircle & rhs)
    {
    if (this == &rhs)
    return *this;
    *itsRadius = rhs.GetRadius();
    return *this;
    }

    const SimpleCircle& SimpleCircle::operator++()
    {
    ++(*itsRadius);
    return *this;
    }

    // Postfix-Operator ++(int).
    const SimpleCircle SimpleCircle::operator++ (int)
    {
    // lokales SimpleCircle-Objekt deklarieren und mit *this initialisieren
    SimpleCircle temp(*this);
    ++(*itsRadius);
    return temp;
    }
    int SimpleCircle::GetRadius() const
    {
    return *itsRadius;
    }
    int main()
    {
    SimpleCircle CircleOne, CircleTwo(9);
    CircleOne++;
    ++CircleTwo;
    cout << "CircleOne: " << CircleOne.GetRadius() << endl;
    cout << "CircleTwo: " << CircleTwo.GetRadius() << endl;
    CircleOne = CircleTwo;
    cout << "CircleOne: " << CircleOne.GetRadius() << endl;
    cout << "CircleTwo: " << CircleTwo.GetRadius() << endl;
    return 0;
    }
  9. FEHLERSUCHE: Was ist falsch an der folgenden Implementierung des Zuweisungsoperators?
    SQUARE SQUARE ::operator=(const SQUARE & rhs)
    {
    itsSide = new int;
    *itsSide = rhs.GetSide();
    return *this;
    }
  1. FEHLERSUCHE: Was ist falsch an der folgenden Implementierung des Additionsoperators?
    VeryShort   VeryShort::operator+ (const VeryShort& rhs)
    {
    itsVal += rhs.GetItsVal();
    return *this;
    }

Tag 11

Quiz

  1. Was ist eine V-Tabelle?
  1. Was ist ein virtueller Destruktor?
  1. Wie deklariert man einen virtuellen Konstruktor?
  1. Wie erzeugt man einen virtuellen Kopierkonstruktor?
  1. Wie rufen Sie eine Elementfunktion einer Basisklasse aus einer abgeleiteten Klasse auf, wenn diese Funktion in der abgeleiteten Klasse überschrieben wurde?
    Basis::Funktionsname();
  2. Wie rufen Sie eine Elementfunktion einer Basisklasse aus einer abgeleiteten Klasse auf, wenn diese Funktion in der abgeleiteten Klasse nicht überschrieben wurde?
    Funktionsname();
  3. Wenn eine Basisklasse eine Funktion als virtuell deklariert hat und eine abgeleitete Klasse beim Überschreiben dieser Klasse den Begriff virtuell nicht verwendet, ist die Funktion immer noch virtuell, wenn sie an eine Klasse der dritten Generation vererbt wird?
  1. Wofür wird das Schlüsselwort protected verwendet?

Übungen

  1. Setzen Sie die Deklaration einer virtuellen Funktion auf, die einen Integer als Parameter übernimmt und void zurückliefert.
    virtual void EineFunktion(int);
  2. Geben Sie die Deklaration einer Klasse Square an, die sich von Rectangle ableitet, die wiederum eine Ableitung von Shape ist.
    class Square : public Rectangle
    {};
  3. Angenommen in Übung 2 übernimmt Shape keine Parameter, Rectangle übernimmt zwei (length und width), aber Square übernimmt nur einen (length). Wie sieht die Konstruktorinitialisierung für Square aus?
    Square::Square(int length):
    Rectangle(length, length){}
  4. Schreiben Sie einen virtuellen Kopierkonstruktor für die Klasse Square (aus Übung 3).
    class Square
    {
    public:
    // ...
    virtual Square * clone() const { return new Square(*this); }
    // ...
    };
  5. FEHLERSUCHE: Was ist falsch in diesem Codefragment?
    void EineFunktion (Shape);
    Shape * pRect = new Rectangle;
    EineFunktion(*pRect);
  1. FEHLERSUCHE: Was ist falsch in diesem Codefragment?
    class Shape()
    {
    public:
    Shape();
    virtual ~Shape();
    virtual Shape(const Shape&);
    };

Tag 12

Quiz

  1. Wie lauten die ersten und letzten Elemente von EinArray[25]?
    EinArray[0], EinArray[24]
  2. Wie deklariert man ein mehrdimensionales Array?
  1. Initialisieren Sie die Elemente des Array aus Frage 2.
    EinArray[2][3][2] = { { {1,2},{3,4},{5,6} }, { {7,8},{9,10},{11,12} } };
  2. Wie viele Elemente enthält das Array EinArray[10][5][20]?
  1. Wie lautet die maximale Anzahl von Elementen, die Sie einer verketteten Liste hinzufügen können?
  1. Können Sie die Index-Notation für eine verkettete Liste verwenden?
  1. Wie lautet das letzte Zeichen in dem String »Barbie ist eine nette Lady«?

Übungen

  1. Deklarieren Sie ein zweidimensionales Array, das ein Tic-Tac-Toe-Brett darstellt.
    int Spielbrett[3][3];
  2. Schreiben Sie einen Code, der alle Elemente in dem Array aus Übung 1 mit 0 initialisiert.
    int Spielbrett[3][3] = { {0,0,0},{0,0,0},{0,0,0} }
  3. Schreiben Sie die Deklaration für eine Node-Klasse, die Integer-Werte aufnimmt.
    class Node
    {
    public:
    Node ();
    Node (int);
    ~Node();
    void SetNext(Node * node) { itsNext = node; }
    Node * GetNext() const { return itsNext; }
    int GetVal() const { return itsVal; }
    void Insert(Node *);
    void Display();
    private:
    int itsVal;
    Node * itsNext;
    };
  4. FEHLERSUCHE: Was ist falsch an folgendem Codefragment?
    unsigned short EinArray[5][4];
    for (int i = 0; i<4; i++)
    for (int j = 0; j<5; j++)
    EinArray[i][j] = i+j;
  1. FEHLERSUCHE: Was ist falsch an folgendem Codefragment?
    unsigned short EinArray[5][4];
    for (int i = 0; i<=5; i++)
    for (int j = 0; j<=4; j++)
    EinArray[i][j] = 0;

Tag 13

Quiz

  1. Was ist eine abwärts gerichtete Typenumwandlung?
  1. Was ist der »vptr«?
  1. Stellen Sie sich vor, Sie haben eine Klasse RoundRect für Rechtecke mit abgerundeten Ecken, die sowohl von Rectangle als auch von Circle abgeleitet ist. Rectangle und Circle sind ihrerseits von Shape abgeleitet. Wie viele Shapes werden dann bei der Instanziierung eines RoundRects erzeugt?
  1. Wenn Horse und Bird von der Klasse Animal als publc virtual Basisklasse abgeleitet sind, rufen dann ihre Konstruktoren den Animal-Konstruktor auf? Wenn Pegasus sowohl von Horse als auch von Bird abgeleitet ist, wie kann Pegasus den Animal-Konstruktor aufrufen?
  1. Deklarieren Sie eine Klasse Vehicle und machen Sie die Klasse zu einem abstrakten Datentyp.
    class Vehicle
    {
    virtual void Move() = 0;
    }
  2. Wenn eine Basisklasse einen ADT darstellt und drei abstrakte Funktionen beinhaltet, wie viele dieser Funktionen müssen dann in den abgeleiteten Klassen überschrieben werden?

Übungen

  1. Setzen Sie die Deklaration für eine Klasse JetPlane auf, die von Rocket und Airplane abgeleitet ist.
    class JetPlane : public Rocket, public Airplane
  2. Setzen Sie die Deklaration für eine Klasse 747 auf, die von der Klasse JetPlane aus Übung 1 abgeleitet ist.
    class 747 : public JetPlane
  3. Schreiben Sie ein Programm, das die Klassen Car und Bus von der Klasse Vehicle ableitet. Deklarieren Sie Vehicle als ADT mit zwei abstrakten Funktionen. Car und Bus sollen keine abstrakten Datentypen sein.
    class Vehicle
    {
    virtual void Move() = 0;
    virtual void Haul() = 0;
    };

    class Car : public Vehicle
    {
    virtual void Move();
    virtual void Haul();
    };

    class Bus : public Vehicle
    {
    virtual void Move();
    virtual void Haul();
    };
  4. Ändern Sie das Programm aus Übung 3 dahingehend, daß die Klasse Car ein abstrakter Datentyp ist, von dem die Klassen SportsCar und Coupe abgeleitet werden. Die Klasse Car soll für eine der abstrakten Funktionen von Vehicle einen Anweisungsteil vorsehen, so daß die Funktion nicht mehr abstrakt ist.
    class Vehicle
    {
    virtual void Move() = 0;
    virtual void Haul() = 0;
    };

    class Car : public Vehicle
    {
    virtual void Move();
    };

    class Bus : public Vehicle
    {
    virtual void Move();
    virtual void Haul();
    };

    class SportsCar : public Car
    {
    virtual void Haul();
    };

    class Coupe : public Car
    {
    virtual void Haul();
    };

Tag 14

Quiz

  1. Können statische Elementvariablen privat sein?
  1. Geben Sie die Deklaration für eine statische Elementvariable an.
    static int staticElement;
  2. Geben Sie die Deklaration für eine statische Funktion an.
    static int EineFunktion();
  3. Geben Sie die Deklaration für einen Zeiger auf eine Funktion an, die long zurückgibt und zwei int-Parameter übernimmt.
    long (* funktion)(int);
  4. Modifizieren Sie den Zeiger in Frage 4 so, daß er ein Zeiger auf eine Elementfunktion der Klasse Car ist.
    long ( Car::*funktion)(int);
  5. Geben Sie die Deklaration für ein Array von zehn Zeigern an, die wie in Frage 5 definiert sind.
    long ( Car::*funktion)(int) dasArray[10];

Übungen

  1. Schreiben Sie ein kurzes Programm, das eine Klasse mit einer Elementvariablen und einer statischen Elementvariablen deklariert. Der Konstruktor soll die Elementvariable initialisieren und die statische Elementvariable inkrementieren. Der Destruktor soll die Elementvariable dekrementieren.
    1:     class myClass
    2: {
    3: public:
    4: myClass();
    5: ~myClass();
    6: private:
    7: int itsMember;
    8: static int itsStatic;
    9: };
    10:
    11: myClass::myClass():
    12: itsMember(1)
    13: {
    14: itsStatic++;
    15: }
    16:
    17: myClass::~myClass()
    18: {
    19: itsStatic--;
    20: }
    21:
    22: int myClass::itsStatic = 0;
    23:
    24: int main()
    25: {}
  2. Verwenden Sie das Programm aus Übung 1, schreiben Sie ein kleines Rahmenprogramm, das drei Objekte erzeugt und dann den Inhalt der Elementvariablen und der statischen Elementvariable anzeigt. Zerstören Sie danach jedes Objekt, und zeigen Sie die Auswirkung auf die statische Elementvariable.
    1:     #include <iostream.h>
    2:
    3: class myClass
    4: {
    5: public:
    6: myClass();
    7: ~myClass();
    8: void ShowMember();
    9: void ShowStatic();
    10: private:
    11: int itsMember;
    12: static int itsStatic;
    13: };
    14:
    15: myClass::myClass():
    16: itsMember(1)
    17: {
    18: itsStatic++;
    19: }
    20:
    21: myClass::~myClass()
    22: {
    23: itsStatic--;
    24: cout << "In Destruktor. ItsStatic: " << itsStatic << endl;
    25: }
    26:
    27: void myClass::ShowMember()
    28: {
    29: cout << "itsMember: " << itsMember << endl;
    30: }
    31:
    32: void myClass::ShowStatic()
    33: {
    34: cout << "itsStatic: " << itsStatic << endl;
    35: }
    36: int myClass::itsStatic = 0;
    37:
    38: int main()
    39: {
    40: myClass obj1;
    41: obj1.ShowMember();
    42: obj1.ShowStatic();
    43:
    44: myClass obj2;
    45: obj2.ShowMember();
    46: obj2.ShowStatic();
    47:
    48: myClass obj3;
    49: obj3.ShowMember();
    50: obj3.ShowStatic();
    51: return 0;
    52: }
  3. Modifizieren Sie das Programm aus Übung 2, indem Sie eine statische Elementfunktion für den Zugriff auf die statische Elementvariable verwenden. Machen Sie die statische Elementvariable privat.
    1:     #include <iostream.h>
    2:
    3: class myClass
    4: {
    5: public:
    6: myClass();
    7: ~myClass();
    8: void ShowMember();
    9: static int GetStatic();
    10: private:
    11: int itsMember;
    12: static int itsStatic;
    13: };
    14:
    15: myClass::myClass():
    16: itsMember(1)
    17: {
    18: itsStatic++;
    19: }
    20:
    21: myClass::~myClass()
    22: {
    23: itsStatic--;
    24: cout << "In Destruktor. ItsStatic: " << itsStatic << endl;
    25: }
    26:
    27: void myClass::ShowMember()
    28: {
    29: cout << "itsMember: " << itsMember << endl;
    30: }
    31:
    32: int myClass::itsStatic = 0;
    33:
    34: void myClass::GetStatic()
    35: {
    36: return itsStatic;
    37: }
    38:
    39: int main()
    40: {
    41: myClass obj1;
    42: obj1.ShowMember();
    43: cout << "itsStatic: " << myClass::GetStatic() << endl;
    44:
    45: myClass obj2;
    46: obj2.ShowMember();
    47: cout << "itsStatic: " << myClass::GetStatic() << endl;
    48:
    49: myClass obj3;
    50: obj3.ShowMember();
    51: cout << "itsStatic: " << myClass::GetStatic() << endl;
    52: return 0;
    53: }
  4. Schreiben Sie einen Zeiger auf Elementfunktionen, der auf die nicht statischen Datenelemente des Programm aus Übung 3 zugreift, und verwenden Sie den Zeiger, um den Wert der Elemente auszugeben.
    1:     #include <iostream.h>
    2:
    3: class myClass
    4: {
    5: public:
    6: myClass();
    7: ~myClass();
    8: void ShowMember();
    9: static int GetStatic();
    10: private:
    11: int itsMember;
    12: static int itsStatic;
    13: };
    14:
    15: myClass::myClass():
    16: itsMember(1)
    17: {
    18: itsStatic++;
    19: }
    20:
    21: myClass::~myClass()
    22: {
    23: itsStatic--;
    24: cout << "In Destruktor. ItsStatic: " << itsStatic << endl;
    25: }
    26:
    27: void myClass::ShowMember()
    28: {
    29: cout << "itsMember: " << itsMember << endl;
    30: }
    31:
    32: int myClass::itsStatic = 0;
    33:
    34: int myClass::GetStatic()
    35: {
    36: return itsStatic;
    37: }
    38:
    39: int main()
    40: {
    41: void (myClass::*PMF) ();
    42:
    43: PMF=myClass::ShowMember;
    44:
    45: myClass obj1;
    46: (obj1.*PMF)();
    47: cout << "itsStatic: " << myClass::GetStatic() << endl;
    48:
    49: myClass obj2;
    50: (obj2.*PMF)();
    51: cout << "itsStatic: " << myClass::GetStatic() << endl;
    52:
    53: myClass obj3;
    54: (obj3.*PMF)();
    55: cout << "itsStatic: " << myClass::GetStatic() << endl;
    56: return 0;
    57: }
  5. Ergänzen Sie die Klasse aus der vorigen Frage um zwei Elementvariablen. Fügen Sie Zugriffsfunktionen hinzu, die den gleichen Rückgabewert und die gleiche Signatur aufweisen und die die Werte dieser Elementvariablen auslesen. Greifen Sie auf diese Funktionen über einen Zeiger auf Elementfunktionen zu.
    1:     #include <iostream.h>
    2:
    3: class myClass
    4: {
    5: public:
    6: myClass();
    7: ~myClass();
    8: void ShowMember();
    9: void ShowSecond();
    10: void ShowThird();
    11: static int GetStatic();
    12: private:
    13: int itsMember;
    14: int itsSecond;
    15: int itsThird;
    16: static int itsStatic;
    17: };
    18:
    19: myClass::myClass():
    20: itsMember(1),
    21: itsSecond(2),
    22: itsThird(3)
    23: {
    24: itsStatic++;
    25: }
    26:
    27: myClass::~myClass()
    28: {
    29: itsStatic--;
    30: cout << "In Destruktor. ItsStatic: " << itsStatic << endl;
    31: }
    32:
    33: void myClass::ShowMember()
    34: {
    35: cout << "itsMember: " << itsMember << endl;
    36: }
    37:
    38: void myClass::ShowSecond()
    39: {
    40: cout << "itsSecond: " << itsSecond << endl;
    41: }
    42:
    43: void myClass::ShowThird()
    44: {
    45: cout << "itsThird: " << itsThird << endl;
    46: }
    47: int myClass::itsStatic = 0;
    48:
    49: int myClass::GetStatic()
    50: {
    51: return itsStatic;
    52: }
    53:
    54: int main()
    55: {
    56: void (myClass::*PMF) ();
    57:
    58: myClass obj1;
    59: PMF=myClass::ShowMember;
    60: (obj1.*PMF)();
    61: PMF=myClass::ShowSecond;
    62: (obj1.*PMF)();
    63: PMF=myClass::ShowThird;
    64: (obj1.*PMF)();
    65: cout << "itsStatic: " << myClass::GetStatic() << endl;
    66:
    67: myClass obj2;
    68: PMF=myClass::ShowMember;
    69: (obj2.*PMF)();
    70: PMF=myClass::ShowSecond;
    71: (obj2.*PMF)();
    72: PMF=myClass::ShowThird;
    73: (obj2.*PMF)();
    74: cout << "itsStatic: " << myClass::GetStatic() << endl;
    75:
    76: myClass obj3;
    77: PMF=myClass::ShowMember;
    78: (obj3.*PMF)();
    79: PMF=myClass::ShowSecond;
    80: (obj3.*PMF)();
    81: PMF=myClass::ShowThird;
    82: (obj3.*PMF)();
    83: cout << "itsStatic: " << myClass::GetStatic() << endl;
    84: return 0;
    85: }

Tag 15

Quiz

  1. Wie erzeugt man eine ist-ein-Beziehung?
  1. Wie erzeugt man eine hat-ein-Beziehung?
  1. Was ist der Unterschied zwischen Einbettung und Delegierung?
  1. Was ist der Unterschied zwischen Delegierung und implementiert mit Hilfe von?
  1. Was ist eine friend-Funktion?
  1. Was ist eine friend-Klasse?
  1. Wenn Dog ein Freund (friend) von Boy ist, ist Boy dann auch ein Freund von Dog?
  1. Wenn Dog ein Freund von Boy ist und Terrier sich von Dog ableitet, ist Terrier dann auch ein Freund von Boy?
  1. Wenn Dog ein Freund von Boy ist und Boy ein Freund von House ist, ist Dog dann auch ein Freund von House?
  1. Wo innerhalb einer Klassendeklaration sollte man friend-Funktion deklarieren?

Übungen

  1. Setzen Sie die Deklaration einer Klasse Animal auf, die ein String-Objekt als Datenelement enthält.
    class Animal:
    {
    private:
    String itsName;
    };
  2. Deklarieren Sie eine Klasse BoundedArray, die ein Array darstellt.
    class BoundedArray : public Array
    {
    //...
    }
  3. Wie deklariert man eine Klasse Menge auf der Grundlage der Klasse Array.
    class Menge : private Array
    {
    // ...
    }
  4. Erweitern Sie Listing 15.1 um einen Einlese-Operator (>>) für die String-Klasse.
    1:        #include <iostream.h>
    2: #include <string.h>
    3:
    4: class String
    5: {
    6: public:
    7: // Konstruktoren
    8: String();
    9: String(const char *const);
    10: String(const String &);
    11: ~String();
    12:
    13: // Überladene Operatoren
    14: char & operator[](int offset);
    15: char operator[](int offset) const;
    16: String operator+(const String&);
    17: void operator+=(const String&);
    18: String & operator= (const String &);
    19: friend ostream& operator<<
    20: ( ostream& _theStream,String& theString);
    21: friend istream& operator>>
    22: ( istream& _theStream,String& theString);
    23: // Allgemeine Zugriffsfunktionen
    24: int GetLen()const { return itsLen; }
    25: const char * GetString() const { return itsString; }
    26: // static int ConstructorCount;
    27:
    28: private:
    29: String (int); // privater Konstruktor
    30: char * itsString;
    31: unsigned short itsLen;
    32:
    33 };
    34:
    35: ostream& operator<<( ostream& theStream,String& theString)
    36: {
    37: theStream << theString.GetString();
    38: return theStream;
    39: }
    40:
    41: istream& operator>>( istream& theStream,String& theString)
    42: {
    43: theStream >> theString.GetString();
    44: return theStream;
    45: }
    46:
    47: int main()
    48: {
    49: String theString("Hello world.");
    50: cout << theString;
    51: return 0;
    52: }
  5. FEHLERSUCHE: Was ist falsch an folgendem Programm?
    1:     #include <iostream.h>
    2:
    3: class Animal;
    4:
    5: void setValue(Animal& , int);
    6:
    7:
    8: class Animal
    9: {
    10: public:
    11: int GetWeight()const { return itsWeight; }
    12: int GetAge() const { return itsAge; }
    13: private:
    14: int itsWeight;
    15: int itsAge;
    16: };
    17:
    18: void setValue(Animal& theAnimal, int theWeight)
    19: {
    20: friend class Animal;
    21: theAnimal.itsWeight = theWeight;
    22: }
    23:
    24: int main()
    25: {
    26: Animal peppy;
    27: setValue(peppy,5);
    28: }
  1. Beheben Sie den Fehler in Übung 5, so daß sich der Code kompilieren läßt.
    1:     #include <iostream.h>
    2:
    3: class Animal;
    4:
    5: void setValue(Animal& , int);
    6:
    7:
    8: class Animal
    9: {
    10: public:
    11: friend void setValue(Animal&, int);
    12: int GetWeight()const { return itsWeight; }
    13: int GetAge() const { return itsAge; }
    14: private:
    15: int itsWeight;
    16: int itsAge;
    17: };
    18:
    19: void setValue(Animal& theAnimal, int theWeight)
    20: {
    21: theAnimal.itsWeight = theWeight;
    22: }
    23:
    24: int main()
    25: {
    26: Animal peppy;
    27: setValue(peppy,5);
    28: return 0;
    29: }
  2. FEHLERSUCHE: Was ist falsch an diesem Code?
    1:     #include <iostream.h>
    2:
    3: class Animal;
    4:
    5: void setValue(Animal& , int);
    6: void setValue(Animal& ,int,int);
    7:
    8: class Animal
    9: {
    10: friend void setValue(Animal& ,int);
    11: private:
    12: int itsWeight;
    13: int itsAge;
    14: };
    15:
    16: void setValue(Animal& theAnimal, int theWeight)
    17: {
    18: theAnimal.itsWeight = theWeight;
    19: }
    20:
    21:
    22: void setValue(Animal& theAnimal, int theWeight, int theAge)
    23: {
    24: theAnimal.itsWeight = theWeight;
    25: theAnimal.itsAge = theAge;
    26: }
    27:
    28: int main()
    29: {
    30: Animal peppy;
    31: setValue(peppy,5);
    32: setValue(peppy,7,9);
    33: }
  1. Beheben Sie den Fehler in Übung 7, so daß sich der Code kompilieren läßt.
    1:     #include <iostream.h>
    2:
    3: class Animal;
    4:
    5: void setValue(Animal& , int);
    6: void setValue(Animal& ,int,int);
    7:
    8: class Animal
    9: {
    10: friend void setValue(Animal& ,int);
    11: friend void setValue(Animal& ,int,int);
    12: private:
    13: int itsWeight;
    14: int itsAge;
    15: };
    16:
    17: void setValue(Animal& theAnimal, int theWeight)
    18: {
    19: theAnimal.itsWeight = theWeight;
    20: }
    21:
    22:
    23: void setValue(Animal& theAnimal, int theWeight, int theAge)
    24: {
    25: theAnimal.itsWeight = theWeight;
    26: theAnimal.itsAge = theAge;
    27: }
    28:
    29: int main()
    30: {
    31: Animal peppy;
    32: setValue(peppy,5);
    33: setValue(peppy,7,9);
    34: return 0;
    35: }

Tag 16

Quiz

  1. Was ist der Ausgabe-Operator, und wozu dient er?
  1. Was ist der Eingabe-Operator und wozu dient er?
  1. Wie lauten die drei Formen von cin.get(), und wo liegen die Unterschiede?
  1. Was ist der Unterschied zwischen cin.read() und cin.getline()?
  1. Wie groß ist die Standardbreite für die Ausgabe eines Integers vom Typ long mit Hilfe des Ausgabe-Operators?
  1. Wie lautet der Rückgabewert des Ausgabe-Operators?
  1. Welche Parameter übernimmt der Konstruktor eines ofstream-Objekts?
  1. Was bewirkt das Argument ios::ate?

Übungen

  1. Schreiben Sie ein Programm, das die vier Standardstreamobjekte cin, cout, cerr und clog verwendet.
    1:     #include <iostream.h>
    2: int main()
    3: {
    4: int x;
    5: cout << "Geben Sie eine Zahl ein: ";
    6: cin >> x;
    7: cout << "You entered: " << x << endl;
    8: cerr << "Uh oh, this to cerr!" << endl;
    9: clog << "Uh oh, this to clog!" << endl;
    10: return 0;
    11: }
  2. Schreiben Sie ein Programm, das den Anwender auffordert, seinen vollständigen Namen einzugeben, und diesen dann auf dem Bildschirm ausgibt.
    1:     #include <iostream.h>
    2: int main()
    3: {
    4: char name[80];
    5: cout << "Geben Sie Ihren vollstaendigen Namen ein: ";
    6: cin.getline(name,80);
    7: cout << "\nSie heissen: " << name << endl;
    8: return 0;
    9: }
  3. Schreiben Sie ein Neufassung von Listing 16.9, das zwar das gleiche bewirkt, jedoch ohne putback() und ignore() auskommt.
    1:      // Listing
    2: #include <iostream.h>
    3:
    4: int main()
    5: {
    6: char ch;
    7: cout << "Geben Sie einen Satz ein: ";
    8: while ( cin.get(ch) )
    9: {
    10: switch (ch)
    11: {
    12: case '!':
    13: cout << '$';
    14: break;
    15: case '#':
    16: break;
    17: default:
    18: cout << ch;
    19: break;
    20: }
    21: }
    22: return 0;
    23: }
  4. Schreiben Sie ein Programm, das einen Dateinamen als Parameter übernimmt und die Datei zum Lesen öffnet. Lesen Sie jedes Zeichen der Datei und lassen Sie nur die Buchstaben und Zeichensetzungssymbole auf dem Bildschirm ausgeben. (Ignorieren Sie alle nichtdruckbaren Zeichen.) Schließen Sie dann die Datei, und beenden Sie das Programm.
    1:     #include <fstream.h>
    2: enum BOOL { FALSE, TRUE };
    3:
    4: int main(int argc, char**argv) // liefert 1 bei Fehler
    5: {
    6:
    7: if (argc != 2)
    8: {
    9: cout << "Aufruf: argv[0] <eingabedatei>\n";
    10: return(1);
    11: }
    12:
    13: // Eingabestream oeffnen
    14: ifstream fin (argv[1],ios::binary);
    15: if (!fin)
    16: {
    17: cout << argv[1] <<
    " kann nicht zum Lesen geoeffnet werden.\n";
    18: return(1);
    19: }
    20:
    21: char ch;
    22: while ( fin.get(ch))
    23: if ((ch > 32 && ch < 127) || ch == '\n' || ch == '\t')
    24: cout << ch;
    25: fin.close();
    26: }
  5. Schreiben Sie ein Programm, das seine Befehlszeilenargumente in umgekehrter Reihenfolge und den Programmnamen überhaupt nicht anzeigt.
    1:     #include <fstream.h>
    2:
    3: int main(int argc, char**argv) // liefert 1 bei Fehler
    4: {
    5: for (int ctr = argcÐ1; ctr ; ctr--)
    6: cout << argv[ctr] << " ";
    7: return 0;
    8: }

Tag 17

Quiz

  1. Kann ich Namen, die in einem Namensbereich definiert sind, ohne vorangehende using-Anweisung verwenden?
  1. Was sind die Hauptunterschiede zwischen normalen und unbenannten Namensbereichen?
  1. Was versteht man unter dem Standardnamensbereich?

Übungen

  1. FEHLERSUCHE: Was ist falsch an diesem Programm?
    #include <iostream>

    int main()
    {
    cout << "Hello world!" << end;
    return 0;
    }
  1. Geben Sie drei Möglichkeiten an, das Problem in Übung 1 zu beheben.
    1.    using namespace std;
    2. using std::cout;
    using std::endl;
    3. std::cout << "Hello world!" << std::endl;

Tag 18

Quiz

  1. Worin besteht der Unterschied zwischen objektorientierter und prozeduraler Programmierung?
  1. Welche Phasen umfassen objektorientierte Analyse und Design?
  1. In welcher Beziehung stehen Sequenz- und Kollaborationsdiagramme zueinander?

Übungen

  1. Nehmen Sie an, Sie sollen die Kreuzung zweier großer Straßen (inklusive Ampeln und Fußgängerübergänge) simulieren. Ziel der Simulation ist es herauszufinden, ob die Ampeln so geschaltet werden können, daß ein fließender Verkehr möglich ist.
  1. Nehmen Sie an, die Kreuzung aus Übung 1 läge in einem Vorort von Boston, einer Stadt, die nach Ansicht mancher Leute die unfreundlichsten Straßen in ganz Amerika enthält. Es gibt drei Typen von Bostonern Autofahrern:
  1. Sie werden gebeten, einen Konferenzplaner zu entwerfen. Die Software soll dabei helfen, Treffen einzelner Personen oder Gruppen zu arrangieren und Konferenzräume zu belegen. Identifizieren Sie die wichtigsten Untersysteme.
  1. Entwerfen Sie die Schnittstellen für die Klassen zur Reservierung der Konferenzräume aus Übung 3.

Tag 19

Quiz

  1. Worin besteht der Unterschied zwischen einem Template und einem Makro?
  1. Worin besteht der Unterschied zwischen dem Parameter eines Templates und einer Funktion?
  1. Worin besteht der Unterschied zwischen der Verwendung einer typspezifischen und einer allgemeinen Template-Klasse als Friend?
  1. Ist es möglich, für eine bestimmte Instanz eines Templates ein spezielles Verhalten vorzusehen, daß sich von dem Verhalten für andere Instanzen unterscheidet?
  1. Wie viele statische Variablen werden erzeugt, wenn Sie ein statisches Element in einer Template-Klasse definieren?
  1. Was muß man sich unter den Iteratoren vorstellen, die in der C++-Standard-Bibliothek verwendet werden?
  1. Was ist ein Funktionsobjekt?

Übungen

  1. Setzen Sie ein Template auf, das auf der folgenden List-Klasse basiert:
    class List
    {
    private:

    public:
    List():head(0),tail(0),theCount(0) {}
    virtual ~List();

    void insert( int value );
    void append( int value );
    int is_present( int value ) const;
    int is_empty() const { return head == 0; }
    int count() const { return theCount; }
    private:
    class ListCell
    {
    public:
    ListCell(int value, ListCell *cell = 0):val(value),next(cell){}
    int val;
    ListCell *next;
    };
    ListCell *head;
    ListCell *tail;
    int theCount;
    };

Und so könnte die Implementierung des Templates aussehen:

template <class Type>
class List
{

public:
List():head(0),tail(0),theCount(0) { }
virtual ~List();

void insert( Type value );
void append( Type value );
int is_present( Type value ) const;
int is_empty() const { return head == 0; }
int count() const { return theCount; }

private:
class ListCell
{
public:
ListCell(Type value, ListCell *cell = 0):val(value),next(cell){}
Type val;
ListCell *next;
};

ListCell *head;
ListCell *tail;
int theCount;
};
  1. Setzen Sie eine Implementierung für die (Nicht-Template-Version der) Klasse List auf.
    void List::insert(int value)
    {
    ListCell *pt = new ListCell( value, head );
    assert (pt != 0);

    // leere Liste
    if ( head == 0 ) tail = pt;

    head = pt;
    theCount++;
    }

    void List::append( int value )
    {
    ListCell *pt = new ListCell( value );
    if ( head == 0 )
    head = pt;
    else
    tail->next = pt;

    tail = pt;
    theCount++;
    }

    int List::is_present( int value ) const
    {
    if ( head == 0 ) return 0;
    if ( head->val == value || tail->val == value )
    return 1;

    ListCell *pt = head->next;
    for (; pt != tail; pt = pt->next)
    if ( pt->val == value )
    return 1;

    return 0;
    }
  2. Setzen Sie eine Implementierung für die Template-Version auf.
    template <class Type>
    List<Type>::~List()
    {
    ListCell *pt = head;

    while ( pt )
    {
    ListCell *tmp = pt;
    pt = pt->next;
    delete tmp;
    }
    head = tail = 0;
    }

    template <class Type>
    void List<Type>::insert(Type value)
    {
    ListCell *pt = new ListCell( value, head );
    assert (pt != 0);

    // leere Liste
    if ( head == 0 ) tail = pt;

    head = pt;
    theCount++;
    }

    template <class Type>
    void List<Type>::append( Type value )
    {
    ListCell *pt = new ListCell( value );
    if ( head == 0 )
    head = pt;
    else
    tail->next = pt;

    tail = pt;
    theCount++;
    }

    template <class Type>
    int List<Type>::is_present( Type value ) const
    {
    if ( head == 0 ) return 0;
    if ( head->val == value || tail->val == value )
    return 1;

    ListCell *pt = head->next;
    for (; pt != tail; pt = pt->next)
    if ( pt->val == value )
    return 1;

    return 0;
    }
  3. Deklarieren Sie drei List-Objekte: eine Liste von Strings, eine Liste von Cats und eine Liste von Integern.
    List<String> string_list;
    List<Cat> Cat_List;
    List<int> int_List;
  4. FEHLERSUCHE: Was stimmt nicht an dem nachfolgenden Code? (Gehen Sie davon aus, daß das List-Template definiert ist und mit Cat die Klasse aus den vorangehenden Kapiteln des Buches gemeint ist.)
    List<Cat> Cat_List;
    Cat Felix;
    CatList.append( Felix );
    cout << "Felix ist " <<
    ( Cat_List.is_present( Felix ) ) ? "" : "nicht " << "da\n";
  1. Deklarieren Sie eine friend-Operator == für List.
    friend int operator==( const Type& lhs, const Type& rhs );
  2. Implementieren Sie den friend-Operator == für List.
    template <class Type>
    int List<Type>::operator==( const Type& lhs, const Type& rhs )
    {
    // zuerst die Laengen vergleichen
    if ( lhs.theCount != rhs.theCount )
    return 0; // unterschiedliche Laengen

    ListCell *lh = lhs.head;
    ListCell *rh = rhs.head;

    for(; lh != 0; lh = lh.next, rh = rh.next )
    if ( lh.value != rh.value )
    return 0;

    return 1; // Laengen gleich
    }
  3. Gibt es mit dem Operator == die gleichen Probleme wie in Übung 5?
  1. Implementieren Sie eine Template-Funktion swap(), die zwei Variablen austauscht.
    // Template swap:
    // fuer Type muessen Zuweisung und Kopierkonstruktor definiert sein
    template <class Type>
    void swap( Type& lhs, Type& rhs)
    {
    Type temp( lhs );
    lhs = rhs;
    rhs = temp;
    }
  2. Implementieren Sie die Klasse SchoolClass aus Listing 19.8 als list-Container. Verwenden Sie die push_back()-Funktion, um vier Studenten in den list-Container aufzunehmen. Gehen Sie dann den Container durch, und setzen Sie das Alter der Schüler um jeweils ein Jahr herauf.
    #include <list>

    template<class T, class A>
    void ShowList(const list<T, A>& aList); // list-Eigenschaften ausgeben

    typedef list<Student> SchoolClass;

    int main()
    {
    Student Harry("Harry", 18);
    Student Sally("Sally", 15);
    Student Bill("Bill", 17);
    Student Peter("Peter", 16);

    SchoolClass GrowingClass;
    GrowingClass.push_back(Harry);
    GrowingClass.push_back(Sally);
    GrowingClass.push_back(Bill);
    GrowingClass.push_back(Peter);
    ShowList(GrowingClass);

    cout << "Ein Jahr spaeter;\n";

    for (SchoolClass::iterator i = GrowingClass.begin();
    i != GrowingClass.end(); ++i)
    i->SetAge(i->GetAge() + 1);

    ShowList(GrowingClass);

    return 0;
    }

    //
    // list-Eigenschaften ausgeben
    //
    template<class T, class A>
    void ShowList(const list<T, A>& aList)
    {
    for (list<T, A>::const_iterator ci = aList.begin();
    ci != aList.end(); ++ci)
    cout << *ci << "\n";

    cout << endl;
    }
  3. Erweitern Sie Übung 10 und verwenden Sie ein Funktionsobjekt, um die Daten der einzelnen Schüler auszugeben.
    #include <algorithm>

    template<class T>
    class Print
    {
    public:
    void operator()(const T& t)
    {
    cout << t << "\n";
    }
    };

    template<class T, class A>
    void ShowList(const list<T, A>& aList)
    {
    Print<Student> PrintStudent;

    for_each(aList.begin(), aList.end(), PrintStudent);

    cout << endl;
    }

Tag 20

Quiz

  1. Was ist eine Exception?
  1. Was ist ein try-Block?
  1. Was ist eine catch-Anweisung?
  1. Welche Informationen kann eine Exception enthalten?
  1. Wann werden Exception-Objekte erzeugt?
  1. Sollte man Exceptions als Wert oder als Referenz übergeben?
  1. Fängt eine catch-Anweisung eine abgeleitete Exception ab, wenn sie nach der Basisklasse sucht?
  1. In welcher Reihenfolge sind zwei catch-Anweisungen einzurichten, wenn die eine Objekte der Basisklasse und die andere Objekte der abgeleiteten Klasse abfängt?
  1. Was bedeutet die Anweisung catch(...)?
  1. Was ist ein Haltepunkt?

Übungen

  1. Erstellen Sie einen try-Block, eine catch-Anweisung und eine einfache Exception.
    #include <iostream.h>
    class OutOfMemory {};
    int main()
    {

    try
    {
    int *myInt = new int;
    if (myInt == 0)
    throw OutOfMemory();
    }
    catch (OutOfMemory)
    {
    cout << "Speicher konnte nicht reserviert werden!\n";
    }
    return 0;
    }
  2. Modifizieren Sie das Ergebnis aus Übung 1: Nehmen Sie in die Exception-Klasse Daten und eine passende Zugriffsfunktion auf. Verwenden Sie diese Elemente im catch-Block.
    #include <iostream.h>
    #include <stdio.h>
    #include <string.h>
    class OutOfMemory
    {
    public:
    OutOfMemory(char *);
    char* GetString() { return itsString; }
    private:
    char* itsString;
    };

    OutOfMemory::OutOfMemory(char * theType)
    {
    itsString = new char[80];
    char warning[] = "Nicht genuegend Speicher fuer: ";
    strncpy(itsString,warning,60);
    strncat(itsString,theType,19);
    }

    int main()
    {

    try
    {
    int *myInt = new int;
    if (myInt == 0)
    throw OutOfMemory("int");
    }
    catch (OutOfMemory& theException)
    {
    cout << theException.GetString();
    }
    return 0;
    }
  3. Wandeln Sie die Klasse aus Übung 2 in eine Hierarchie von Exception-Klassen um. Modifizieren Sie den catch-Block, um die abgeleiteten Objekte und die Basisobjekte zu benutzen.
    1:     #include <iostream.h>
    2:
    3: // Abstrakter Datentyp fuer Exceptions
    4: class Exception
    5: {
    6: public:
    7: Exception(){}
    8: virtual ~Exception(){}
    9: virtual void PrintError() = 0;
    10: };
    11:
    12: // Abgleitete Klasse fuer Speicherprobleme.
    13: // Achtung: Keine Speicherallokation in dieser Klasse!
    14: class OutOfMemory : public Exception
    15: {
    16: public:
    17: OutOfMemory(){}
    18: ~OutOfMemory(){}
    19: virtual void PrintError();
    20: private:
    21: };
    22:
    23: void OutOfMemory::PrintError()
    24: {
    25: cout << "Nicht genuegend Speicher!!\n";
    26: }
    27:
    28: // Abgeleitete Klasse fuer ungueltige Zahlenwerte
    29: class RangeError : public Exception
    30: {
    31: public:
    32: RangeError(unsigned long number){badNumber = number;}
    33: ~RangeError(){}
    34: virtual void PrintError();
    35: virtual unsigned long GetNumber() { return badNumber; }
    36: virtual void SetNumber(unsigned long number) {
    badNumber = number;}
    37: private:
    38: unsigned long badNumber;
    39: };
    40:
    41: void RangeError::PrintError()
    42: {
    43: cout << "Wert " << GetNumber() <<
    " ausserhalb des gueltigen Bereichs!!\n";
    44: }
    45:
    46: void MyFunction(); // Prototyp
    47:
    48: int main()
    49: {
    50: try
    51: {
    52: MyFunction();
    53: }
    54: // Nur ein catch-Block erforderlich, nutzt virtuelle
    55: // Funktionen.
    56: catch (Exception& theException)
    57: {
    58: theException.PrintError();
    59: }
    60: return 0;
    61: }
    62:
    63: void MyFunction()
    64: {
    65: unsigned int *myInt = new unsigned int;
    66: long testNumber;
    67: if (myInt == 0)
    68: throw OutOfMemory();
    69: cout << "Geben Sie einen int-Wert ein: ";
    70: cin >> testNumber;
    71: // dieser etwas seltsame Test sollte durch
    72: // mehrere Tests ersetzt werden
    73: if (testNumber > 3768 || testNumber < 0)
    74: throw RangeError(testNumber);
    75:
    76: *myInt = testNumber;
    77: cout << "OK. myInt: " << *myInt;
    78: delete myInt;
    79: }
  4. Modifizieren Sie das Programm aus Übung 3, so daß es drei Ebenen für Funktionsaufrufe enthält.
    1:     #include <iostream.h>
    2:
    3: // Abstrakter Datentyp fuer Exceptions
    4: class Exception
    5: {
    6: public:
    7: Exception(){}
    8: virtual ~Exception(){}
    9: virtual void PrintError() = 0;
    10: };
    11:
    12: // Abgleitete Klasse fuer Speicherprobleme.
    13: // Achtung: Keine Speicherallokation in dieser Klasse!
    14: class OutOfMemory : public Exception
    15: {
    16: public:
    17: OutOfMemory(){}
    18: ~OutOfMemory(){}
    19: virtual void PrintError();
    20: private:
    21: };
    22:
    23: void OutOfMemory::PrintError()
    24: {
    25: cout << "Nicht genuegend Speicher!!\n";
    26: }
    27:
    28: // Abgeleitete Klasse fuer ungueltige Zahlenwerte
    29: class RangeError : public Exception
    30: {
    31: public:
    32: RangeError(unsigned long number){badNumber = number;}
    33: ~RangeError(){}
    34: virtual void PrintError();
    35: virtual unsigned long GetNumber() { return badNumber; }
    36: virtual void SetNumber(unsigned long number) {
    badNumber = number;}
    37: private:
    38: unsigned long badNumber;
    39: };
    40:
    41: void RangeError::PrintError()
    42: {
    43: cout << "Wert " << GetNumber() <<
    " ausserhalb des gueltigen Bereichs!!\n";
    44: }
    45:
    46: // Prototypen
    47: void MyFunction();
    48: unsigned int * FunctionTwo();
    49: void FunctionThree(unsigned int *);
    50:
    51: int main()
    52: {
    53: try
    54: {
    55: MyFunction();
    56: }
    57: // Nur ein catch-Block erforderlich, nutzt virtuelle
    58: // Funktionen.
    59: catch (Exception& theException)
    60: {
    61: theException.PrintError();
    62: }
    63: return 0;
    64: }
    65:
    66: unsigned int * FunctionTwo()
    67: {
    68: unsigned int *myInt = new unsigned int;
    69: if (myInt == 0)
    70: throw OutOfMemory();
    71: return myInt;
    72: }
    73:
    74: void MyFunction()
    75: {
    76: unsigned int *myInt = FunctionTwo();
    77:
    78: FunctionThree(myInt);
    79: cout << "OK. myInt: " << *myInt;
    80: delete myInt;
    81: }
    82:
    83: void FunctionThree(unsigned int *ptr)
    84: {
    85: long testNumber;
    86: cout << "Geben Sie einen int-Wert ein: ";
    87: cin >> testNumber;
    88: // dieser etwas seltsame Test sollte durch
    89: // mehrere Tests ersetzt werden
    90: if (testNumber > 3768 || testNumber < 0)
    91: throw RangeError(testNumber);
    92: *ptr = testNumber;
    93: }
  5. FEHLERSUCHE: Wo verbirgt sich der Fehler in folgendem Code?
    class xOutOfMemory
    {
    public:
    xOutOfMemory(){ theMsg = new char[20];
    strcpy(theMsg,"Kein Speicher mehr");}
    ~xOutOfMemory(){ delete [] theMsg; cout
    << "Speicher wiederhergestellt." << endl; }
    char * Message() { return theMsg; }
    private:
    char * theMsg;
    };

    main()
    {
    try
    {
    char * var = new char;
    if ( var == 0 )
    {
    xOutOfMemory * px =
    new xOutOfMemory;
    throw px;
    }
    }

    catch( xOutOfMemory * theException )
    {
    cout << theException->Message() <<endl;
    delete theException;
    }
    return 0;
    }

Tag 21

Quiz

  1. Was versteht man unter dem Schutz vor Mehrfachdeklarationen?
  1. Wie weisen Sie den Compiler an, den Inhalt der Zwischendatei auszugeben, um die Arbeit des Präprozessors zu kontrollieren?
  1. Worin liegt der Unterschied zwischen #define debug 0 und #undef debug?
  1. Was bewirkt der Komplementoperator?
  1. Wie unterscheiden sich die Verknüpfungen OR und XOR?
  1. Worin unterscheiden sich die Operatoren & und &&?
  1. Worin unterscheiden sich die Operatoren| und ||?

Übungen

  1. Schreiben Sie Anweisungen, um einen Schutz vor Mehrfachdeklarationen für die Header-Datei STRING.H zu realisieren.
    #ifndef STRING_H
    #define STRING_H
    ...
    #endif
  2. Schreiben Sie ein assert-Makro, das eine Fehlermeldung zusammen mit dem Dateinamen und der Zeilennummer ausgibt, wenn für die Fehlersuche die Ebene 2 definiert ist, und das ausschließlich eine Fehlermeldung (ohne Dateinamen und Zeilennummer) ausgibt, wenn für die Fehlersuche die Ebene 1 festgelegt ist, und das bei Ebene 0 überhaupt nichts macht.
    1:     #include <iostream.h>
    2:
    3: #ifndef DEBUG
    4: #define ASSERT(x)
    5: #elif DEBUG == 1
    6: #define ASSERT(x) \
    7: if (! (x))\
    8: { \
    9: cout << "Fehler!! Assert " << #x << " gescheitert\n"; \
    10: }
    11: #elif DEBUG == 2
    12: #define ASSERT(x) \
    13: if (! (x) ) \
    14: { \
    15: cout << "Fehler!! Assert " << #x << " gescheitert\n"; \
    16: cout << " in Zeile " << __LINE __ << "\n; \
    17: cout << " in Datei " << __LINE __ << "\n; \
    18: }
    19: #endif
  3. Schreiben Sie ein Makro DPrint, das auf die Definition von DEBUG testet. Wenn DEBUG definiert ist, soll das Makro den als Parameter übergebenen Wert anzeigen.
    #ifndef DEBUG
    #define DPRINT(string)
    #else
    #define DPRINT(STRING) cout << #STRING ;
    #endif
  4. Schreiben Sie ein Programm, das zwei Zahlen addiert, ohne den Additionsoperator (+) zu verwenden. Hinweis: Arbeiten Sie mit Bit-Operatoren.



vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


© Markt&Technik Verlag, ein Imprint der Pearson Education Deutschland GmbH