In diesem Praktikum wird Jupyter verwendet, um Ihnen die grundlegende Funktionsweise von C++ näher zu bringen. Weder das Beschäftigen mit den Jupyter-Dateien, noch die Bearbeitung der Aufgaben in den Jupyter-Dateien ist verpflichtend. Ziel der Jupyter-Dateien ist es, Ihnen die Sprache C++ näher zu bringen, falls Sie bis jetzt wenig oder gar keine Erfahrung mit C++ haben.
Die Funktionsweise von Jupyter unterscheidet sich an einigen Stellen recht stark von dedizierten Entwicklungsumgebungen, die meistens einen deutlich größeren Funktionsumfang zur Fehlerbehebung und Organisation umfangreicher Softwareprojekte aufweisen. Für die hier vorgestellten Beispiele ist dieser allerdings nicht unbedingt notwendig; darüberhinaus entfällt so anfangs die individuelle Installation und Konfiguration, bei der sich erfahrungsgemäß häufig Probleme ergeben können. Jupyter kann von Ihnen einfach im Browser verwendet werden, wobei eine Instanz auf den Servern der RWTH läuft. Es ist ebenfalls möglich, Jupyter lokal zu installieren, was für die Bearbeitung dieses Praktikums aber nicht notwendig ist. Im folgenden soll Ihnen ein kurzer Überblick darüber gegeben werden, wie Sie mit Jupyter arbeiten können.
Sollten Sie bereits eine funktionierende Installation von Visual Studio oder einer anderen C++ Entwicklungsumgebung haben, ist es natürlich ebenfalls möglich, die Übungsaufgaben darin zu lösen.
In Jupyter-Notebooks wird Text und Code in Zellen aufgeteilt. Diese sind prinzipiell frei verschiebbar und können auch kopiert oder gelöscht werden, jedoch sind Reihenfolge und Anzahl in den folgenden Notebooks aus naheliegenden Gründen bereits passend gewählt und müssen im Allgemeinen nicht von Ihnen verändert werden. Zellen können (mit Markdown formatierten) Text oder Code beinhalten. Die Auswahl geschieht je Zelle über ein Dropdown-Menü in der Toolbar.
Ausführen einer einzelnen Zelle: -Button. Dabei ist zu beachten, dass der Code in einmal ausgeführten Zellen innerhalb des gesamten Notebooks seine Gültigkeit behält, sodass beispielsweise dort definierte Variablen oder Methoden in weiteren Zellen verwendet werden können. Die Reihenfolge der Ausführung wird in kleinen Ziffern links neben der Zelle angegeben.
Ausführen aller Zellen eines Notebooks: im Menü: Run Run All Cells oder -Button (startet vorher den Kernel neu, was also insbesondere die Werte aller Variablen zurücksetzt)
pro Zelle kann nur eine Methode implementiert werden, sonst kommt
es zu Fehlermeldungen wie
function definition is not allowed here. In den
Jupyter-Files mit den Übungsaufgaben ist daher angegeben, in welcher
Zelle welche Methode einer Klasse definiert werden soll.
Zellen können durch einen Klick auf den blauen Balken links ein- und ausgeblendet werden. Die Lösungen zu den Übungsaufgaben sind im Normalfall ausgeblendet.
Um zu verstehen, wie sich C++ verhält, wenn Code in einer anderen Reihenfolge ausgeführt wird, muss in Jupyter der Code nicht umgestellt werden. Es genügt, die auszuführende Zelle zu markieren und den -Button zu drücken.
Die Verwendung von Namespaces sollte aufgrund der fehlenden
Aufteilung in Dateien vermieden werden, da dies schnell unübersichtlich
werden könnte und erfahrungsgemäß häufig zu wenig hilfreichen
Fehlermeldungen führen kann. Unter anderem bedeutet das auch, dass die
durchaus verbreitete Zeile using namespace std; wegfällt
und stattdessen der Präfix std:: vor bestimmte Ausdrücke
wie string, cout usw. geschrieben
wird.
In den Notebooks, bei denen Sie eine eigene Implementierung erstellen sollen, kann es hilfreich sein, sich die Aufgabenstellung und später die Lösung nebeninander anzuzeigen, anstatt immer nach oben und unten zu scrollen. Dafür wählen Sie nach einem Rechtsklick auf den aktuellen Tab die Option "New View for Notebook" aus, was eine neue Ansicht desselben Notebooks erstellt. Diese beiden Ansichten bleiben im Hintergrund synchronisiert, können aber unabhängig voneinader durchgescrollt werden.
| New View for Notebook | Ergebnis |
|---|---|
|
|
// Beispiel: Führen Sie diese Zelle aus!
#include <iostream>
std::cout << "Hello World" << std::endl;
Hin und wieder kann es notwenig sein, den Kernel neu zu starten (-Button). Dies ist vor allem dann erforderlich, wenn Code in einer falschen Reihenfolge ausgeführt wird. Da Jupyter dazu ermuntert, Zellen nicht nur linear von oben nach unten auszuführen, kann dies häufiger auftreten.
In dem verwendeten Kernel gibt es in Zusammenhang mit der Operatorenüberladung einen Fehler. Daher ist in Jupyter-Dateien ein zusätzlicher Schritt notwendig:
std::ostream & operator<<(std::ostream& out, const Train& train)
{
train.vPrintProperties(out);
return out;
}#define OPERATOR operator<<
std::ostream & OPERATOR(std::ostream& out, const Train& train)
{
train.vPrintProperties(out);
return out;
}
#undef OPERATORHier wird also temporär eine Präprozessorkonstante definiert, die in der folgenden Funktionsdefinition verwendet werden kann. Für die Verwendung des auf diese Weise überladenen Operators ergeben sich keinerlei Unterschiede.