{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## A. Klassen mit mehrere Konstruktoren\n", "\n", "**Aufgabe:**\n", "\n", "- Implementieren Sie in eine Klasse `Vector` mit folgenden Eigenschaften (Details siehe [taskA.Vector.hpp](taskA.Vector.hpp)):\n", " - Eine private Membervariable vom Typ `std::vector`\n", " - Drei Konstruktoren\n", " - Eine `const` Memberfunktion `print()`.\n", "- Nach der Implementierung von `Vector`: Aktivieren Sie in [taskA.cpp](taskA.cpp) alle gekennzeichneten Stellen (die jetzt kompilieren sollten).\n", "\n", "**Demonstration:** Kompilieren Sie Ihr Programm, führen Sie es aus, und erklären Sie in eigenen Worten den Vorteil mehrerer Konstruktoren." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## B. Abgeleitete Klassen und dynamische Speicherverwaltung (*new/delete*)\n", "\n", "**Aufgabe:**\n", "\n", "- Gegeben ist eine abstrakte Schnittstellenklasse `Device` ([taskB.Device.hpp](taskB.Device.hpp))\n", "- Ebenso gegeben sind folgende Klassen, die die Schnittstelle `Device` implementieren: \n", " - `WashingMachine` ([taskB.WashingMachine.hpp](taskB.WashingMachine.hpp)) \n", " - `Train` ([taskB.Train.hpp](taskB.Train.hpp))\n", " \n", "- Implementieren Sie eine weitere Klasse `Car` ([taskB.Car.hpp](taskB.Car.hpp)) die ebenfalls die Schnittstelle `Device` implementiert\n", "- Erweitern Sie die `main`-Funktion in [taskB.cpp](taskB.cpp):\n", " - Allozieren Sie mit `new` dynamische Instanzen Ihrer Klasse und fügen Sie die Zeiger auf diese Instanzen zum bereits vorhandenen Vektor hinzu.\n", " - Deallozieren Sie am Ende alle dynamische allozieren Instanzen mit `delete`\n", "- Speicherlecks:\n", " - Überprüfen Sie ob Ihr Programmdurchlauf Speicherlecks aufweist, indem Sie mit `-fsanitize=address` kompilieren und das Programm ausführen.\n", " - Sie können ein Speicherleck provozieren, indem Sie kein `delete` verwenden (also keine Deallokation durchführen).\n", "\n", "**Demonstration:** \n", "- Erklären Sie in eigenen Worten, welchen Vorteil eine Schnittstellenklasse als Basisklasse bietet; welche Einschränkungen hatten Sie z.B. bei der Wahl der Membervariblen für Ihre Klasse `Car`?\n", "- Kompilieren Sie Ihr Programm mit der Compiler-Option `-fsanitize=address` und führen Sie Ihr Programm aus; provozieren Sie ein Speicherleck und erklären Sie in eigenen Worten das Problem.\n", "\n", "**Wichtiger allgemeiner Hinweis:** Explizite dynamische Speicherverwaltung (`new`/`delete`) sollte **immer nur gekapselt** mit **klarer Regelung des Besitzes** der dynamischen Ressourcen erfolgen: also nur innerhalb einer Klasse/Datenstruktur." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "**CMake:** Sie können (sofern Ihr Compiler dies unterstützt) die oben erwähnte Option auch an CMake übergeben:\n", "\n", "```shell\n", "cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug -D CMAKE_CXX_FLAGS=\"-fsanitize=address\"\n", "cmake --build build --target taskC\n", "./build/taskC\n", "```" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## C. Generische Funktion/Klassen (*templates*)\n", "\n", "In der Datei [taskC.one.hpp](taskC.one.hpp) sind im Namensraum `one` zwei Sätze von Funktionsüberladungen `add` und `sum` gegeben.\n", "\n", "**Aufgabe 1:**\n", "\n", "- Implementieren Sie in [taskC.two.hpp](taskC.two.hpp) im Namensraum `two` zwei Funktions-Templates `add` und `sum`, die Anstelle von `one::add` und `one::sum` verwendet werden können\n", "- Nach der Implementierung: stellen Sie in [taskC.cpp](taskC.cpp) den verwendeten Namensraum von `one` auf `two` um, und überprüfen Sie die Funktionalität (die sich nicht geändert haben sollte).\n", "\n", "**Demonstration 1:** Kompilieren Sie Ihr Programm und führen Sie es aus. Könnten Sie mittels Ihrer zwei Funktions-Templates nun (neben `int` und `double`) beliebige andere Typen addieren und summieren? Welche Voraussetzungen gelten für die Template-Typen bei Ihren Funktionen?\n", "\n", "**Aufgabe 2:**\n", "\n", "- Kopieren Sie die Datei [taskA.Vector.hpp](taskA.Vector.hpp) als [taskA.VectorT.hpp](taskA.VectorT.hpp):\n", " - Benennen Sie die Klasse in `VectorT` um\n", " - **Entfernen Sie den dritten Konstruktor** (den mit dem `std::function` Parameter), da eine Umsetzung erweiterte C++-Kenntnisse erfordern wuerde. \n", " - Verwandeln Sie die Klasse in ein Klassen-Template, indem Sie den im Vektor abgespeicherten Typ als Template-Typ verwenden:\n", " ```cpp\n", " template \n", " struct VectorT {\n", " private:\n", " std::vector data;\n", " ...\n", " };\n", " ```\n", "\n", "**Demonstration 2:** Erklären Sie, wie Sie bei der Umwandlung für von `Vector` zu `VectorT` vorgegangen sind." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.12.2" } }, "nbformat": 4, "nbformat_minor": 2 }