Wissensspeicher 15

Baumtraversierung

  • Tiefensuche
    • inorder: links, Knoten, rechts → sortierte Ausgabe bei binärem Suchbaum
    • preorder: Knoten, links, rechts
    • postorder: links, rechts, Knoten
  • Breitensuche
    • breadth-first-search
    • Zuerst alle Knoten einer Ebene abarbeiten, dann absteigen

Graphen

  • Verallgemeinerung eines Baumes
  • Besteht aus Kanten und Knoten
  • Gerichtet und ungereichtet
  • Wichtiges Werkzeug in der Informatik zur Modellierung

pages/Kapitel10-page-01.svg

pages/Kapitel10-page-02.svg

pages/Kapitel10-page-03.svg

pages/Kapitel10-page-04.svg

pages/Kapitel10-page-05.svg

pages/Kapitel10-page-06.svg

pages/Kapitel10-page-07.svg

pages/Kapitel10-page-08.svg

pages/Kapitel10-page-09.svg

pages/Kapitel10-page-10.svg

pages/Kapitel10-page-11.svg

pages/Kapitel10-page-12.svg

pages/Kapitel10-page-13.svg

pages/Kapitel10-page-14.svg

pages/Kapitel10-page-15.svg

pages/Kapitel10-page-16.svg

pages/Kapitel10-page-17.svg

pages/Kapitel10-page-18.svg

pages/Kapitel10-page-19.svg

pages/Kapitel10-page-20.svg

pages/Kapitel10-page-21.svg

pages/Kapitel10-page-22.svg

pages/Kapitel10-page-23.svg

pages/Kapitel10-page-24.svg

pages/Kapitel10-page-25.svg

pages/Kapitel10-page-26.svg

pages/Kapitel10-page-27.svg

pages/Kapitel10-page-28.svg

Live-Demo - Vererbung 1

#include <iostream>

using namespace std;

class KString {
private:
	char* mString;
	int mLength;

public:
	KString(char const* s)	{
		mLength = strlen(s);              // Länge ohne '\0'
		mString = new char[mLength + 1];  // + 1 wegen '\0'
		strcpy(mString, s);               // kopiert s nach mString
	}
	void setString(char const* s) {
		int length = strlen(s);
		if (length > mLength) {
			delete[] mString;
			mString = new char[length + 1];
		}
		strcpy(mString, s);
		mLength = length;
	}
	char* getString() { return mString; }
	int length() { return mLength; }
	void print() { cout << mString << endl; }
	~KString() {
		delete[] mString;
	}
};

class KVersalien : public KString {
private:
	void up() {
		for (int i = 0; i < mLength; ++i) {
			if (islower(mString[i])) {
				mString[i] = toupper(mString[i]);
			}
		}
	}

public:
	KVersalien(char const* s) : mLength(0) { }
	void print() { cout << mString << endl; }
	void setString(char const* s) {
		KString::setString(s);
		up();
	}
};

int main() {
  KString s1{"erster String"};
  s1.print();
  cout << "s1.length()=" << s1.length() << endl;

	return 0;
}
compiler

pages/Kapitel10-page-29.svg

pages/Kapitel10-page-30.svg

pages/Kapitel10-page-31.svg

pages/Kapitel10-page-32.svg

pages/Kapitel10-page-33.svg

pages/Kapitel10-page-34.svg

pages/Kapitel10-page-35.svg

pages/Kapitel10-page-36.svg

pages/Kapitel10-page-37.svg

pages/Kapitel10-page-38.svg

pages/Kapitel10-page-39.svg

pages/Kapitel10-page-40.svg

pages/Kapitel10-page-41.svg

pages/Kapitel10-page-42.svg

pages/Kapitel10-page-43.svg

pages/Kapitel10-page-44.svg

pages/Kapitel10-page-45.svg

pages/Kapitel10-page-46.svg

pages/Kapitel10-page-47.svg

pages/Kapitel10-page-48.svg

Sichtbarkeit der Vererbung gibt
Obergrenze für Sichtbarkeit vor

Live-Demo - public-Vererbung

#include <iostream>

using namespace std;

class A {
private:
    int pi = 3;
protected:
    int plank = 6;
public:
    int boltzmann = 1;
};

class B : public A {
public:
    int getPlank() { return plank; }
    int getBoltzmann() { return boltzmann; }
};

int main() {
    B b;

    cout << "pi = " << b.pi << endl;
    cout << "boktzmann = " << b.boltzmann << endl;
    cout << "plank = " << b.plank << endl;

	return 0;
}
compiler

Live-Demo - protected-Vererbung

#include <iostream>

using namespace std;

class A {
private:
    int pi = 3;
protected:
    int plank = 6;
public:
    int boltzmann = 1;
};

class B : protected A {
public:
    int getPlank() { return plank; }
    int getBoltzmann() { return boltzmann; }
};

int main() {
    B b;

    // Die Ausgabe von B::pi geht nicht, da private.
    cout << "boktzmann = " << b.boltzmann << endl;
    cout << "plank = " << b.plank << endl;

	return 0;
}
compiler

Live-Demo - private-Vererbung

#include <iostream>

using namespace std;

class A {
private:
    int pi = 3;
protected:
    int plank = 6;
public:
    int boltzmann = 1;
};

class B : private A {
public:
    int getPlank() { return plank; }
    int getBoltzmann() { return boltzmann; }
};

int main() {
    B b;

    // Die Ausgabe von B::pi geht nicht, da private.
    cout << "boktzmann = " << b.boltzmann << endl;
    cout << "plank = " << b.plank << endl;

	return 0;
}
compiler

pages/Kapitel10-page-49.svg

pages/Kapitel10-page-50.svg

pages/Kapitel10-page-51.svg

pages/Kapitel10-page-52.svg

pages/Kapitel10-page-53.svg

pages/Kapitel10-page-54.svg

pages/Kapitel10-page-55.svg

pages/Kapitel10-page-56.svg

pages/Kapitel10-page-57.svg

pages/Kapitel10-page-58.svg

pages/Kapitel10-page-59.svg

pages/Kapitel10-page-60.svg

pages/Kapitel10-page-61.svg

pages/Kapitel10-page-62.svg

Live-Demo - Funktionen der Oberklasse nutzen

#include <iostream>

using namespace std;

class KString {
protected:
	char* mString;
	int mLength;

public:
	KString(char const* s)	{
		mLength = strlen(s);              // Länge ohne '\0'
		mString = new char[mLength + 1];  // + 1 wegen '\0'
		strcpy(mString, s);               // kopiert s nach mString
	}
	void setString(char const* s) {
		int length = strlen(s);
		if (length > mLength) {
			delete[] mString;
			mString = new char[length + 1];
		}
		strcpy(mString, s);
		mLength = length;
	}
	char* getString() { return mString; }
	int length() { return mLength; }
	void print() { cout << mString << endl; }
	~KString() {
		delete[] mString;
	}
};

class KVersalien : public KString {
private:
	void up() {
		for (int i = 0; i < mLength; ++i) {
			if (islower(mString[i])) {
				mString[i] = toupper(mString[i]);
			}
		}
	}

public:
	KVersalien(char const* s) : KString(s) { up(); }
	void print() { cout << mString << endl; }
	void setString(char const* s) {
            // TODO
	}
};

int main() {
  KString s1{"erster String"};
  s1.print();
  cout << "s1.length()=" << s1.length() << endl;

	return 0;
}
compiler

pages/Kapitel10-page-63.svg

pages/Kapitel10-page-64.svg

pages/Kapitel10-page-65.svg

pages/Kapitel10-page-66.svg

pages/Kapitel10-page-67.svg

pages/Kapitel10-page-68.svg

pages/Kapitel10-page-69.svg

Live-Demo - Vererbungstest

#include <iostream>

using namespace std;

class KString {
protected:
	char* mString;
	int mLength;

public:
	KString(char const* s)	{
		mLength = strlen(s);              // Länge ohne '\0'
		mString = new char[mLength + 1];  // + 1 wegen '\0'
		strcpy(mString, s);               // kopiert s nach mString
	}
	void setString(char const* s) {
		int length = strlen(s);
		if (length > mLength) {
			delete[] mString;
			mString = new char[length + 1];
		}
		strcpy(mString, s);
		mLength = length;
	}
	char* getString() { return mString; }
	int length() { return mLength; }
	void print() { cout << mString << endl; }
	~KString() {
		delete[] mString;
	}
};

class KVersalien : public KString {
private:
	void up() {
		for (int i = 0; i < mLength; ++i) {
			if (islower(mString[i])) {
				mString[i] = toupper(mString[i]);
			}
		}
	}

public:
	KVersalien(char const* s) : KString(s) { up(); }
	void print() { cout << mString << endl; }
	void setString(char const* s) { KString::setString(s); up(); }
};

int main() {
	KString s1{"erster String"};
	s1.print();
	cout << "s1.length()=" << s1.length() << endl;

	s1.setString("kurz");
	s1.print();
	cout << "s1.length()=" << s1.length() << endl;
	cout << endl;

	s1.setString("erster String ueberschrieben");
	s1.print();
	cout << "s1.length()=" << s1.length() << endl;
	cout << endl;

	KVersalien v1{s1.getString()};
	v1.print();
	cout << "v1.length()=" << v1.length() << endl;
	cout << endl;

	v1.setString("versalien-string auch nochmal ueberschrieben");
	v1.print();
	cout << "v1.length()=" << v1.length() << endl;
	cout << endl;

	return 0;
}
compiler

pages/Kapitel10-page-70.svg

pages/Kapitel10-page-71.svg

pages/Kapitel10-page-72.svg

pages/Kapitel10-page-73.svg

pages/Kapitel10-page-74.svg

pages/Kapitel10-page-75.svg

pages/Kapitel10-page-76.svg

pages/Kapitel10-page-77.svg

pages/Kapitel10-page-78.svg

pages/Kapitel10-page-79.svg

pages/Kapitel10-page-80.svg

pages/Kapitel10-page-81.svg

pages/Kapitel10-page-82.svg

Live-Demo - Mehrfachvererbung

#include <iostream>

using namespace std;

class Pferd {
public: 
    string geraeusch() {
       return "wiehern"; 
    } 
};

class Mensch {
public:
    string geraeusch() {
       return "hallo"; 
    }
    void print() {
        cout << "Ich bin ein Mensch!" << endl;
    }
};

class Chimaere : public Mensch, public Pferd {
public:
    string geraeusch() {
       return Mensch::geraeusch() + Pferd::geraeusch(); 
    }
};


int main() {
    Chimaere c;

    cout << c.geraeusch() << endl;
    cout << c.Mensch::geraeusch() << endl;
    cout << c.Pferd::geraeusch() << endl;

    c.print();

	return 0;
}
compiler

pages/Kapitel10-page-83.svg

pages/Kapitel10-page-84.svg

pages/Kapitel10-page-85.svg

pages/Kapitel10-page-86.svg

pages/Kapitel10-page-87.svg

pages/Kapitel10-page-88.svg

pages/Kapitel10-page-89.svg

pages/Kapitel10-page-90.svg

pages/Kapitel10-page-91.svg

pages/Kapitel10-page-92.svg

pages/Kapitel10-page-93.svg

pages/Kapitel10-page-94.svg

pages/Kapitel10-page-95.svg

pages/Kapitel10-page-96.svg

pages/Kapitel10-page-97.svg

pages/Kapitel10-page-98.svg

pages/Kapitel10-page-99.svg

pages/Kapitel10-page-100.svg

pages/Kapitel10-page-101.svg

pages/Kapitel10-page-102.svg

pages/Kapitel10-page-103.svg

pages/Kapitel10-page-104.svg

pages/Kapitel10-page-105.svg

pages/Kapitel10-page-106.svg

pages/Kapitel10-page-107.svg

pages/Kapitel10-page-108.svg

pages/Kapitel10-page-109.svg

pages/Kapitel10-page-110.svg

pages/Kapitel10-page-111.svg

pages/Kapitel10-page-112.svg

pages/Kapitel10-page-113.svg

pages/Kapitel10-page-114.svg

pages/Kapitel10-page-115.svg

pages/Kapitel10-page-116.svg

pages/Kapitel10-page-117.svg

Wissensspeicher 16

Vererbung

  • Weitergabe von Daten (Attributen) und Operationen (Methoden) an andere Klassen

  • Wiederverwendung und ggf. Spezialisierung von Programmcode (siehe KVersalien::setString())

  • Syntax: class B : public class A {

  • Auch Mehrfachvererbung möglich

  • Sichtbarkeit der Vererbung gibt obere Grenze für die weitere Sichtbarkeit an

    • class B : public class A {: Sichtbarkeit aller geerbten Elemente bleibt erhalten
    • class B : protected class A {: Sichtbarkeit aller geerbten Elemente wird auf Unterklassen beschränkt
    • class B : private class A {: Sichtbarkeit aller geerbten Elemente wird auf diese Klasse beschränkt
  • Aufruf von Methoden der Oberklasse mit Klassennamen: KString::setString()

  • Aufruf des Konstruktors der Oberklasse in der Initializer List:

    KVersalien(.. s) : KString(s) {}

  • Aufrufe der Konstruktoren der Oberklassen wird dringend empfohlen

pages/Kapitel10-page-118.svg

pages/Kapitel10-page-119.svg

pages/Kapitel10-page-120.svg

pages/Kapitel10-page-121.svg

pages/Kapitel10-page-122.svg

pages/Kapitel10-page-123.svg

pages/Kapitel10-page-124.svg

pages/Kapitel10-page-125.svg

pages/Kapitel10-page-126.svg

pages/Kapitel10-page-127.svg

pages/Kapitel10-page-128.svg

pages/Kapitel10-page-129.svg

pages/Kapitel10-page-130.svg

pages/Kapitel10-page-131.svg

pages/Kapitel10-page-132.svg

pages/Kapitel10-page-133.svg

pages/Kapitel10-page-134.svg

pages/Kapitel10-page-135.svg

pages/Kapitel10-page-136.svg

pages/Kapitel10-page-137.svg

pages/Kapitel10-page-138.svg

pages/Kapitel10-page-139.svg

pages/Kapitel10-page-140.svg

„Beispiel mit 3 Klassen: Testprogramm” - Revisited

Was kann man bei der Implementierung der Klassen Mann und Frau verbessern?

(Betrachtet das Problem eher gesellschaftlich – im Jahr 2024.)

  • Die Methoden heirateMann() und heirateFrau sind nicht mehr zeitgemäß
  • Eigentlich soll eine Person eine Partnerschaft eingehen → gehePartnerschaftEin()
  • Funktionalität in die gemeinsame Oberklasse verlagern
class Person {
private:
    Person *mParterIn;
    void gehePartnerschaftEin(Person *p) { mPartnerIn = p; }
    /* ... Rest ... */
public:
    /* ... Rest ... */
    Person* partnerInVon() { return mPartnerIn; }
    bool heirate(Person *p) {
        if (p == nullptr) {
            return false;
        }
        if (p->partnerInVon() != nullptr ||
            this->partnerInVon() != nullptr) {
            return false;
        }
        p->gehePartnerschaftEin(this);
        this->gehePartnerschaftEin(p);
        return true;
    }
};

One Variable to Rule Them All

  • Instanzen von Unterklassen können Zeigervariablen der Oberklasse zugewiesen werden
  • Nützlich bei der Speicherung von Objekten unterschiedlichen Typs mit gemeinsamer Oberklasse
  • Beispiel: Liste von Personen (Mann, Frau, Divers) oder TU-Angehörige(r) (Student:in, Mitarbeiter:in, Prof)
class TUPerson { /* ... */ };
class Student : public TUPerson { /* ... */ };
class Employee : public TUPerson { /* ... */ };

int main() {
    list<TUPerson*> members;

    TUPerson *p = new Student();
    members.enqueue(p);

    p = new Employee();
    members.enqueue(p);

    return 0;
}

Live-Demo - Variablenzuweisung

#include <iostream>
#include <list>

using namespace std;

class A {
public:
    void print() { cout << "Hello!" << endl; }
};

class B : public A {
public:
    void print() { cout << "Bye!" << endl; }
};

class C : public A {
public:
    void print() { cout << "Ciao!" << endl; }
};

int main() {
    list<A*> elements;
    A a;
    B b;
    C c1, c2;

    elements.push_back(&b);
    elements.push_back(&c1);
    elements.push_back(&c2);
    elements.push_back(&a);

    for (A *elem : elements) {
        elem->print();
    }

	return 0;
}
compiler

Aufruf der korrekten Variante?
→ virtuelle Methoden
→ Kapitel 11

pages/Kapitel10-page-141.svg

pages/Kapitel10-page-142.svg

pages/Kapitel10-page-143.svg

pages/Kapitel10-page-144.svg

pages/Kapitel10-page-145.svg

pages/Kapitel10-page-146.svg

pages/Kapitel10-page-147.svg