[C++/de] fixed wrong spelling (#3579)

* Added [C++/de]

* [C++/de] filename fixed.

* [C++/de] language code in filename added

* [C++/de] fixed wrong spelling

* [C++/en] smart pointer added
This commit is contained in:
LamdaLamdaLamda 2019-08-03 20:18:39 +02:00 committed by Divay Prakash
parent 7fca9b47a9
commit 41f2b7f168
2 changed files with 157 additions and 110 deletions

View File

@ -72,7 +72,7 @@ void func(); // function which may accept any number of arguments
int* ip = nullptr; int* ip = nullptr;
// C standard headers are available in C++. // C standard headers are available in C++.
// C headers end in .h, while // C headers end in .h, while
// C++ headers are prefixed with "c" and have no ".h" suffix. // C++ headers are prefixed with "c" and have no ".h" suffix.
// The C++ standard version: // The C++ standard version:
@ -761,7 +761,7 @@ failure:
// things are a little cleaner, but still sub-optimal. // things are a little cleaner, but still sub-optimal.
void doSomethingWithAFile(const char* filename) void doSomethingWithAFile(const char* filename)
{ {
FILE* fh = fopen(filename, "r"); // Open the file in read mode FILE* fh = fopen(filename, "r"); // Open the file in shared_ptrread mode
if (fh == nullptr) if (fh == nullptr)
throw std::runtime_error("Could not open the file."); throw std::runtime_error("Could not open the file.");
@ -814,6 +814,57 @@ void doSomethingWithAFile(const std::string& filename)
// - Mutexes using lock_guard and unique_lock // - Mutexes using lock_guard and unique_lock
/////////////////////
// Smart Pointer
/////////////////////
// Generally a smart pointer is a class, which wraps a "raw pointer" (usage of "new"
// respectively malloc/calloc in C). The goal is to be able to
// manage the lifetime of the object being point to without explicitly deleting
// the object. The term itself simply describes a set of pointers with the
// mentioned abstraction.
// Basically smart pointers should preferred over raw pointers, to prevent
// risky memory leaks, which happens if you forget to delete the object.
// Usage of a raw pointer:
Dog* ptr = new Dog();
ptr->bark();
delete ptr;
// With the usage of smart pointers you dont have to worry about the deletion
// of a object anymore.
// A smart pointer describes a policy, to count the references on the
// pointer. As matter of fact the objects gets destroyed when the last
// reference on the object gets destroyed.
// Usage of "std::shared_ptr":
void foo()
{
// Its not longer necessary to delete the Dog.
std::shared_ptr<Dog> doggo(new Dog());
doggo->bark();
}
// Beware of possible circular references!!!
// There will be always a reference, so it will be never destroyed!
std::shared_ptr<Dog> doggo_one (new Dog());
std::shared_ptr<Dog> doggo_two (new Dog());
doggo_one = doggo_two; // p1 references p2
doggo_two = doggo_one; // p2 references p1
// As mentioned before there is a set of smart pointers. The way you have to
// use it, is always the same.
// This leads us to question, when to use which one?
// std::unique_ptr - use it when you just want to hold one reference on
// the same object.
// std::shared_ptr - use it when you want to hold multiple references on the
// same object and want to make sure that it´s de-allocated
// when all refences are gone.
// std::weak_ptr - use it when you want to hold multiple references from
// different places for references for which it´s no problem
// tp de-allocate.
///////////////////// /////////////////////
// Containers // Containers
///////////////////// /////////////////////
@ -877,7 +928,7 @@ cout << ST.size(); // will print the size of set ST
// Output: 0 // Output: 0
// NOTE: for duplicate elements we can use multiset // NOTE: for duplicate elements we can use multiset
// NOTE: For hash sets, use unordered_set. They are more efficient but // NOTE: For hash sets, use unordered_set. They are more efficient but
// do not preserve order. unordered_set is available since C++11 // do not preserve order. unordered_set is available since C++11
// Map // Map
@ -906,7 +957,7 @@ cout << it->second;
// Output: 26 // Output: 26
// NOTE: For hash maps, use unordered_map. They are more efficient but do // NOTE: For hash maps, use unordered_map. They are more efficient but do
// not preserve order. unordered_map is available since C++11. // not preserve order. unordered_map is available since C++11.
// Containers with object keys of non-primitive values (custom classes) require // Containers with object keys of non-primitive values (custom classes) require

View File

@ -23,9 +23,11 @@ entworfen wurde um,
- generische Programmierung zu unterstützen - generische Programmierung zu unterstützen
Durch seinen Syntax kann sie durchaus schwieriger und komplexer als neuere Sprachen sein. Durch seinen Syntax kann sie durchaus schwieriger und komplexer als neuere Sprachen sein.
Sie ist weit verbeitet, weil sie in Maschinen-Code compiliert, welches direkt vom Prozessor ausgeführt
Sie ist weit verbreitet, weil sie in Maschinen-Code kompiliert, welches direkt vom Prozessor ausgeführt
werden kann und somit eine strikte Kontrolle über die Hardware bietet und gleichzeitig werden kann und somit eine strikte Kontrolle über die Hardware bietet und gleichzeitig
High-Level-Features wie generics, exceptions und Klassen enthält. (wie C) High-Level-Features wie generics, exceptions und Klassen enthält.
Diese Kombination aus Geschwindigkeit und Funktionalität bildet C++ und ist eine der Diese Kombination aus Geschwindigkeit und Funktionalität bildet C++ und ist eine der
weitverbreitesten Programmiersprachen. weitverbreitesten Programmiersprachen.
@ -34,19 +36,20 @@ weitverbreitesten Programmiersprachen.
// Vergleich zu C // Vergleich zu C
////////////////// //////////////////
// C++ ist fast eine Untermenge von C and teilt sich grundsätzlich den // C ist fast eine Untermenge von C++ und teilt sich grundsätzlich den
// Syntax für Variablen Deklarationen, primitiven Typen und Funktionen. // Syntax für Variablen Deklarationen, primitiven Typen und Funktionen.
// Wie in C ist der Programmeinsprungpunkt eine Funktion, welche "main" genannt wird und // Wie in C ist der Programmeinsprungpunkt eine Funktion, welche "main" genannt wird und
// einen Ineteger als Rückgabetyp besitzt. // einen Integer als Rückgabetyp besitzt.
// Dieser Wert fungiert als Beendigungsstatus des Programms. // Dieser Wert fungiert als Beendigungsstatus des Programms.
// Siehe: https://de.wikipedia.org/wiki/Return_Code für weitere Informationen // Siehe: https://de.wikipedia.org/wiki/Return_Code für weitere Informationen
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
// Kommandozeilen Argumente werden genauso wie in C über argc und argv übergeben // Kommandozeilen Argumente werden genauso wie in C über argc und argv übergeben
// argc entspricht der Anzahl von Argumenten und argv ist ein Array von C-style // argc entspricht der Anzahl von Argumenten und argv ist ein Array von C-style
// strings (char*), welche die Argumente repräsentieren. // strings (char*), welche die Argumente repräsentieren.
// Das erste Argument ist der Name des Programms welches aufgerufen wird. // Das erste Argument ist der Name des Programms, welches aufgerufen wird.
// Argc und argv können, wenn nicht benötigt, weg gelassen werden, indem // Argc und argv können, wenn nicht benötigt, weg gelassen werden, indem
// die Funktionssignatur "int main()" verwendet wird. // die Funktionssignatur "int main()" verwendet wird.
@ -54,12 +57,12 @@ int main(int argc, char** argv)
return 0; return 0;
} }
// C++ unterscheidet sich in einigen Punkten: // C++ unterscheidet sich in einigen Punkten von C:
// In C++ sind Zeichen-Literale chars // In C++ sind Zeichen-Literale char´s
sizeof('c') == sizeof(char) == 1 sizeof('c') == sizeof(char) == 1
// In C sind Zeichen-Literale ints // In C sind Zeichen-Literale int´s
sizeof('c') == sizeof(int) sizeof('c') == sizeof(int)
// C++ verwendet striktes prototyping // C++ verwendet striktes prototyping
@ -71,8 +74,8 @@ void func(); // Funktion mit beliebiger Anzahl von Argumenten
// Verwende nullptr, anstatt von NULL!!! // Verwende nullptr, anstatt von NULL!!!
int* ip = nullptr; int* ip = nullptr;
// C standard headers sind in C++ verfügbar. // C standard header sind in C++ verfügbar.
// C header enden mit .h, während // C header enden mit .h, während
// C++ header das Präfix "c" besitzen und kein ".h" Suffix verwenden. // C++ header das Präfix "c" besitzen und kein ".h" Suffix verwenden.
// Die C++ Standard Version: // Die C++ Standard Version:
@ -115,10 +118,9 @@ int main()
// Argumente können per Standard für eine Funktion gesetzt werden, // Argumente können per Standard für eine Funktion gesetzt werden,
// wenn diese beim Aufruf nicht bereitgestellt werden. // wenn diese beim Aufruf nicht bereitgestellt werden.
void doSomethingWithInts(int a = 1, int b = 4) void doSomethingWithInts(int a = 1, int b = 4)
{ {
// führe Anweisungen mit "ints" aus. // führe Anweisungen mit "int´s" aus.
} }
int main() int main()
@ -141,18 +143,18 @@ void invalidDeclaration(int a = 1, int b) // Fehler!
// Namespaces stellen einen getrennten Gültigkeitsbereich für Variablen, // Namespaces stellen einen getrennten Gültigkeitsbereich für Variablen,
// Funktionen und andere Deklarationen zur Verfügung. // Funktionen und andere Deklarationen zur Verfügung.
// Namespaces können geschachtelt werden. // Namespaces können geschachtelt werden.
namespace First namespace First
{ {
namespace Nested namespace Nested
{ {
void foo() void foo()
{ {
printf("This is First::Nested::foo\n"); printf("This is First::Nested::foo\n");
} }
} // Ende des Namespaces "Nested" } // Ende des Namespace "Nested"
} // Ende des Namespaces "First" } // Ende des Namespace "First"
namespace Second namespace Second
{ {
void foo() void foo()
{ {
@ -236,8 +238,8 @@ cout << myString; // "Hello Dog"
// C++ besitzt _Referenzen_. // C++ besitzt _Referenzen_.
// Diese sind Pointer-Typen, welche nicht erneut zugewiesen werden können // Diese sind Pointer-Typen, welche nicht erneut zugewiesen werden können
// und nicht Null sein können. // und nicht Null sein können.
// Sie besitzen den selben Synthax wie Variablen. // Sie besitzen den selben Syntax wie Variablen.
// Für die Dereferenzierung ist kein * notwendig und // Für die Dereferenzierung ist kein * notwendig und
// & (die Adresse) wird nicht für die Zuweisung verwendet. // & (die Adresse) wird nicht für die Zuweisung verwendet.
using namespace std; using namespace std;
@ -261,19 +263,18 @@ cout << fooRef; // Gibt "I am bar" aus
// Die Adresse von fooRef verbleibt die selbe, sie verweist immer noch auf foo // Die Adresse von fooRef verbleibt die selbe, sie verweist immer noch auf foo
const string& barRef = bar; // Erzeugt konstante Referenz auf bar. const string& barRef = bar; // Erzeugt konstante Referenz auf bar.
// Wie in C, können konstante Werte ( und Pointer bzw. Referenzen) nicht verändert werden. // Wie in C, können konstante Werte ( und Pointer bzw. Referenzen) nicht verändert werden.
barRef += ". Hi!"; // Fehler: konstante Referenzen können nicht verändert werden. barRef += ". Hi!"; // Fehler: konstante Referenzen können nicht verändert werden.
// Hinweis: bevor wir genauer Referenzen besprechen, schauen wir uns zuerst ein Konzept an // Hinweis: bevor wir genauer Referenzen besprechen, schauen wir uns zuerst ein Konzept an,
// welches als "temporäres Objekt" bezeichnet wird. Gehen wir von folgenden Code aus: // welches als "temporäres Objekt" bezeichnet wird. Gehen wir von folgenden Code aus:
string tempObjectFun() { ... } string tempObjectFun() { ... }
string retVal = tempObjectFun(); string retVal = tempObjectFun();
// Was passiert nun in der zweiten Zeile: // Was passiert nun in der zweiten Zeile:
// - ein String Objekt wird von tempObjectFun zurückgegeben // - ein String Objekt wird von "tempObjectFun" zurückgegeben
// - ein neuer String wird mit dem zurückgegebenen Objekt als Argument für den Konstruktor erzeugt. // - ein neuer String wird mit dem zurückgegebenen Objekt als Argument für den Konstruktor erzeugt.
// - das zurückgegebene Objekt wird zerstört // - das zurückgegebene Objekt wird zerstört
// Das zurückgegbene Objekt wird temporäres Objekt genannt. Temporäre Objekte werden erzeugt // Das zurückgegbene Objekt wird temporäres Objekt genannt. Temporäre Objekte werden erzeugt
@ -285,19 +286,20 @@ foo(bar(tempObjectFun()))
// Nehmen wir an foo und bar existieren. Das Objekt wird von "tempObjectFun" zurückgegeben, // Nehmen wir an foo und bar existieren. Das Objekt wird von "tempObjectFun" zurückgegeben,
// wird an bar übergeben und ist zerstört bevor foo aufgerufen wird. // wird an bar übergeben und ist zerstört bevor foo aufgerufen wird.
// Zurück zu Referenzen. Die Ausnahme, dass die "am Ende des Ausdrucks" Regel ist gültig, // Zurück zu Referenzen. Die Annahme, dass die "am Ende des Ausdrucks" Regel gültig ist,
// wenn das temporäre Objekt an eine konstante Referenz gebunden ist, in welchem Fall das // wenn das temporäre Objekt an eine konstante Referenz gebunden ist, ist der Fall, wenn die Lebensdauer
// Leben auf den aktuellen Gültigkeitsbereich erweitert wird. // auf den aktuellen Gültigkeitsbereich erweitert wird.
void constReferenceTempObjectFun() { void constReferenceTempObjectFun() {
// constRef erhält das temporäre Objekt und ist gültig bis ans Ende der Funktion // constRef erhält das temporäre Objekt und ist gültig bis ans Ende der Funktion
const string& constRef = tempObjectFun(); const string& constRef = tempObjectFun();
... ...
} }
// Eine andere Art von Referenzen wird in C++11 eingeführt und ist speziell für // Eine andere Art von Referenzen wurde in C++11 eingeführt und ist speziell für
// temporäre Objekte. Es ist nicht möglich Variablen des Typs zu besitzen, aber // temporäre Objekte. Es ist nicht möglich Variablen des Typs zu besitzen, aber
// Vorrechte bei der Auflösung. // Vorrechte bei der Auflösung zu besitzen.
void someFun(string& s) { ... } // Reguläre Referenz void someFun(string& s) { ... } // Reguläre Referenz
void someFun(string&& s) { ... } // Referenz auf ein temporäres Objekt void someFun(string&& s) { ... } // Referenz auf ein temporäres Objekt
@ -310,8 +312,8 @@ someFun(tempObjectFun()); // Ruft die Funktion mit der temporären Referenz auf
basic_string(const basic_string& other); basic_string(const basic_string& other);
basic_string(basic_string&& other); basic_string(basic_string&& other);
// Nehmen wir an, wir erzeugen einen neuen String eines temporären Objekts (welches später // Nehmen wir an, wir erzeugen einen neuen String eines temporären Objekts (welches später
// zerstört wird), hierbei existiert ein effizienterer Konstruktor. Dieses Konzept wird // zerstört wird), hierbei existiert ein effizienterer Konstruktor. Dieses Konzept wird
// als "move semantics" bezeichnet (bewegen eines Objekts in ein anderes in C++). // als "move semantics" bezeichnet (bewegen eines Objekts in ein anderes in C++).
///////////////////// /////////////////////
@ -346,18 +348,18 @@ enum ECarTypes : uint8_t
void WriteByteToFile(uint8_t InputValue) void WriteByteToFile(uint8_t InputValue)
{ {
// Serialisierung von InputValue in eine Datei // Serialisierung von "InputValue" in eine Datei
} }
void WritePreferredCarTypeToFile(ECarTypes InputCarType) void WritePreferredCarTypeToFile(ECarTypes InputCarType)
{ {
// Das enum wird implizit zu einem "uint8_t" konvertiert. Bedingt dadurch, dass // Das enum wird implizit zu einem "uint8_t" konvertiert. Bedingt dadurch, dass
// es sich um ein enum handelt. // es sich um ein "enum" handelt.
WriteByteToFile(InputCarType); WriteByteToFile(InputCarType);
} }
// Nicht immer ist es gewünscht, dass enums zu einem Integer oder zu einem anderen // Nicht immer ist es gewünscht, dass enum´s zu einem Integer oder zu einem anderen
// enum umgewandelt werden. Daher ist es möglich eine enum-Klasse zu erzeugen, welche // enum umgewandelt werden. Daher ist es möglich eine enum-Klasse zu erzeugen, welche
// nicht implizit umgewandelt wird. // nicht implizit umgewandelt wird.
enum class ECarTypes : uint8_t enum class ECarTypes : uint8_t
{ {
@ -374,8 +376,8 @@ void WriteByteToFile(uint8_t InputValue)
void WritePreferredCarTypeToFile(ECarTypes InputCarType) void WritePreferredCarTypeToFile(ECarTypes InputCarType)
{ {
// Wird nicht kompilieren, da ECarTypes ein "uint8_t" ist, da das enum // Wird nicht kompilieren, da "ECarTypes" ein "uint8_t" ist, da das enum
// als "enum class" deklariert wurde! // als "enum class" deklariert wurde!
WriteByteToFile(InputCarType); WriteByteToFile(InputCarType);
} }
@ -401,15 +403,15 @@ public:
// Standard Konstruktor // Standard Konstruktor
Dog(); Dog();
// Member-Funktonensdeklaration (Implementierung folgt) // Member-Funktionsdeklaration (Implementierung folgt).
// Bemerkung: std::string statt der Verwendung von namespace std; // Bemerkung: std::string statt der Verwendung von namespace std;
// "using namespace" sollte niemals in einem header verwendet werden. // "using namespace" sollte niemals in einem header verwendet werden.
void setName(const std::string& dogsName); void setName(const std::string& dogsName);
void setWeight(int dogsWeight); void setWeight(int dogsWeight);
// Funktionen, die Objekte nicht ändern sollte mit const deklariert werden. // Funktionen, die Objekte nicht ändern, sollten mit const deklariert werden.
// Funktionen müssen explizit als "virtual" deklariert werden, um in einer // Funktionen müssen explizit als "virtual" deklariert werden, um in einer
// abgeleiteten Klassen überschrieben zu werden. // abgeleiteten Klassen überschrieben zu werden.
// Aus performance Gründen sind Funktionen nicht per default virtual. // Aus performance Gründen sind Funktionen nicht per default virtual.
virtual void print() const; virtual void print() const;
@ -419,24 +421,24 @@ public:
void bark() const { std::cout << name << " barks!\n"; } void bark() const { std::cout << name << " barks!\n"; }
// Neben Konstruktoren, bietet C++ Destruktoren. // Neben Konstruktoren, bietet C++ Destruktoren.
// Diese werden aufgerufen, wenn ein Objekt freigegeben wird oder // Diese werden aufgerufen, wenn ein Objekt freigegeben wird oder
// seinen Wertebereich verlässt. // seinen Wertebereich verlässt.
// Dies ermöglicht mächtige Paradigmen, wie auch RAII. // Dies ermöglicht mächtige Paradigmen, wie auch RAII.
// Destruktoren sollten virtual sein, wenn eine Klasse von ihr // Destruktoren sollten virtual sein, wenn eine Klasse von ihr
// abgeleitet wird. Ist dieser nicht virtual, dann wird der // abgeleitet wird. Ist dieser nicht virtual, dann wird der
// Destruktor der abgeleiteten Klasse nicht aufgerufen, insofern // Destruktor der abgeleiteten Klasse nicht aufgerufen, insofern
// das Objekt durch eine Referenz/Pointer der Basisklasse entfernt wird. // das Objekt durch eine Referenz/Pointer der Basisklasse entfernt wird.
virtual ~Dog(); virtual ~Dog();
}; // Ein Semikolon schließt die Definition der Klasse ab. }; // Ein Semikolon schließt die Definition der Klasse ab.
// Klassen-Member-Funktionen sind üblicherweise in der .cpp Datei implmentiert. // Klassen-Member-Funktionen sind üblicherweise in der .cpp Datei implementiert.
Dog::Dog() Dog::Dog()
{ {
std::cout << "A dog has been constructed\n"; std::cout << "A dog has been constructed\n";
} }
// Objekte sollten als Referenz übergeben werden und wenn diese nicht // Objekte sollten als Referenz übergeben werden und wenn diese nicht
// verändert werden sollen, sollte das Objekt als const Referenz übergeben werden. // verändert werden sollen, sollte das Objekt als const Referenz übergeben werden.
void Dog::setName(const std::string& dogsName) void Dog::setName(const std::string& dogsName)
{ {
@ -468,8 +470,6 @@ int main()
return 0; return 0;
} // Ausgabe: "Goodbye Barkley" } // Ausgabe: "Goodbye Barkley"
// Vererbung:
// Diese Klasse erbt alles was public bzw. protected ist von der Dog-Klasse // Diese Klasse erbt alles was public bzw. protected ist von der Dog-Klasse
// und darüber hinaus auch private Methoden/Attribute, jedoch kann auf diese // und darüber hinaus auch private Methoden/Attribute, jedoch kann auf diese
// nicht direkt zugegriffen werden. Lediglich über public/procted getter/setter. // nicht direkt zugegriffen werden. Lediglich über public/procted getter/setter.
@ -481,7 +481,7 @@ public:
// Überschreibt das Verhalten der "print" Funktion für alle "OwnedDogs". // Überschreibt das Verhalten der "print" Funktion für alle "OwnedDogs".
// Siehe: http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping // Siehe: http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping
// für eine grundlegende Einführung in "Subtype Polymorphismus". // für eine grundlegende Einführung in "Subtype Polymorphismus".
// Das "override" Schlüsselwort ist optional, aber stellt sicher, dass die // Das "override" Schlüsselwort ist optional, aber stellt sicher, dass die
// Methode der Basisklasse tatsächlich überschrieben wurde. // Methode der Basisklasse tatsächlich überschrieben wurde.
void print() const override; void print() const override;
@ -555,7 +555,7 @@ Point& Point::operator+=(const Point& rhs)
return *this; return *this;
} }
int main () int main ()
{ {
Point up (0,1); Point up (0,1);
Point right (1,0); Point right (1,0);
@ -574,23 +574,23 @@ int main ()
// Templates in C++ werden in erster Linie dafür verwendet generisch zu programmieren. // Templates in C++ werden in erster Linie dafür verwendet generisch zu programmieren.
// Sie unterstützen explizite und partielle Spezialisierung und darüber hinaus können // Sie unterstützen explizite und partielle Spezialisierung und darüber hinaus können
// sie für funktionale Klassen verwendet werden. // sie für funktionale Klassen verwendet werden.
// Tatsächlich bilden templates die Turing-Vollständigkeit // Tatsächlich bilden templates die Turing-Vollständigkeit
// (universelle Programmierbarkeit) ab. // (universelle Programmierbarkeit) ab.
// Zu Beginn ein einführendes Beispiel der generischen Programmierung. // Zu Beginn ein einführendes Beispiel der generischen Programmierung.
// Die Definition einer Klasse bzw. Funktion, welche mit dem Typ T parametriert wird. // Die Definition einer Klasse bzw. Funktion, welche mit dem Typ T parametriert wird.
template<class T> template<class T>
class Box class Box
{ {
public: public:
// T repräsentiert an dieser Stelle einen beliebigen Typen. // T repräsentiert an dieser Stelle einen beliebigen Typen.
void insert(const T&) { ... } void insert(const T&) { ... }
}; };
// Während der Kompilierung generiert der Kompiler Kopien für jedes Template, wobei // Während der Kompilierung generiert der Compiler Kopien für jedes template, wobei
// hierbei die Parameter substituiert werden. Somit muss bei jedem Aufruf die gesamte // hierbei die Parameter substituiert werden. Somit muss bei jedem Aufruf die gesamte
// Definition der Klasse zur Verfügung stehen. Aus diesem Grund wird ein Template // Definition der Klasse zur Verfügung stehen. Aus diesem Grund wird ein Template
// komplett im header definiert. // komplett im header definiert.
// Erzeugung einer Template-Klasse auf dem stack: // Erzeugung einer Template-Klasse auf dem stack:
@ -609,7 +609,7 @@ boxOfBox.insert(intBox);
// Manchmal ist folgende Notation anzutreffen: // Manchmal ist folgende Notation anzutreffen:
// template<typename T> // template<typename T>
// Das 'class' Schlüsselwort und das 'typename' Schlüsselwort // Das 'class' Schlüsselwort und das 'typename' Schlüsselwort
// sind fast identisch hinsichtlich der Funktionalität. Weitere // sind fast identisch hinsichtlich der Funktionalität. Weitere
// Informationen auf: http://en.wikipedia.org/wiki/Typename // Informationen auf: http://en.wikipedia.org/wiki/Typename
// Eine template-Funktion: // Eine template-Funktion:
@ -623,7 +623,7 @@ void barkThreeTimes(const T& input)
// Hierbei ist zu beachten, dass an dieser Stelle nichts über den Typen des Parameters // Hierbei ist zu beachten, dass an dieser Stelle nichts über den Typen des Parameters
// definiert wurde. Der Kompiler wird bei jedem Aufruf bzw. jeder Erzeugung den Typen // definiert wurde. Der Kompiler wird bei jedem Aufruf bzw. jeder Erzeugung den Typen
// prüfen. Somit funktioniert die zuvor definiert Funktion für jeden Typ 'T', die die // prüfen. Somit funktioniert die zuvor definierte Funktion für jeden Typ 'T', die die
// const Methode 'bark' implementiert hat. // const Methode 'bark' implementiert hat.
Dog fluffy; Dog fluffy;
@ -632,14 +632,14 @@ barkThreeTimes(fluffy); // Gibt "Fluffy barks" dreimal aus.
// Template Parameter müssen keine Klassen sein. // Template Parameter müssen keine Klassen sein.
template<int Y> template<int Y>
void printMessage() void printMessage()
{ {
cout << "Learn C++ in " << Y << " minutes!" << endl; cout << "Learn C++ in " << Y << " minutes!" << endl;
} }
// Des Weiteren können templates aus Effizienzgründen genauer spezifiziert werden. // Des Weiteren können templates aus Effizienzgründen genauer spezifiziert werden.
// Selbstverständlich sind reale-Problemen, welche genauer spezifiziert werden nicht // Selbstverständlich sind reale-Problemen, welche genauer spezifiziert werden nicht
// derart trivial. Auch wenn alle Parameter explizit definiert wurden, muss die // derart trivial. Auch wenn alle Parameter explizit definiert wurden, muss die
// Funktion oder Klasse als template deklariert werden. // Funktion oder Klasse als template deklariert werden.
template<> template<>
void printMessage<10>() void printMessage<10>()
@ -655,17 +655,17 @@ printMessage<10>(); // Gibt "Learn C++ faster in only 10 minutes!" aus.
// Ausnahme Behandlungen (Exception-Handling) // Ausnahme Behandlungen (Exception-Handling)
///////////////////// /////////////////////
// Die Standard Bibliothek bietet einige Exceptions. // Die Standard Bibliothek bietet einige exceptions.
// Siehe: http://en.cppreference.com/w/cpp/error/exception. // Siehe: http://en.cppreference.com/w/cpp/error/exception.
// Grundsätzlich können alle Typen als Exception geworfen werden. // Grundsätzlich können alle Typen als exception geworfen werden.
#include <exception> #include <exception>
#include <stdexcept> #include <stdexcept>
// Alle Exceptions, die in dem "try" Block geworfen werden, können mittels // Alle exceptions, die in dem "try" Block geworfen werden, können mittels
// "catch" abgefangen werden. // "catch" abgefangen werden.
try try
{ {
// Exceptions sollten nicht auf dem heap mithilfe // exceptions sollten nicht auf dem heap mithilfe
// von "new" allokiert werden. // von "new" allokiert werden.
throw std::runtime_error("A problem occurred"); throw std::runtime_error("A problem occurred");
} }
@ -690,7 +690,7 @@ catch (...)
// RAII steht für "Resource Acquisition Is Initialization". // RAII steht für "Resource Acquisition Is Initialization".
// Oft wird dies als eines der wichtigsten Paradigmen in C++ betrachtet. // Oft wird dies als eines der wichtigsten Paradigmen in C++ betrachtet.
// RAII beschreibt das Konzept, dass der Konstruktor für ein Objekt // RAII beschreibt das Konzept, dass der Konstruktor für ein Objekt
// die Ressourcen akquiriert und der Destruktor diese freigibt. // die Ressourcen akquiriert und der Destruktor diese freigibt.
// Zum Verständnis, warum dies sinnvoll ist, nachfolgend // Zum Verständnis, warum dies sinnvoll ist, nachfolgend
@ -726,7 +726,7 @@ bool doSomethingWithAFile(const char* filename)
return false; // Fehler "melden". return false; // Fehler "melden".
} }
if (!doSomethingElseWithIt(fh)) if (!doSomethingElseWithIt(fh))
{ {
fclose(fh); // File handle schließen. fclose(fh); // File handle schließen.
return false; // Fehler "melden". return false; // Fehler "melden".
@ -770,12 +770,12 @@ void doSomethingWithAFile(const char* filename)
doSomethingWithTheFile(fh); doSomethingWithTheFile(fh);
doSomethingElseWithIt(fh); doSomethingElseWithIt(fh);
} }
catch (...) catch (...)
{ {
// Im Fehlerfall sollte sichergestellt sein, dass die // Im Fehlerfall sollte sichergestellt sein, dass die
// Datei geschlossen wird. // Datei geschlossen wird.
fclose(fh); fclose(fh);
throw; // Erneutes werfen der Exception throw; // Erneutes werfen der exception
} }
fclose(fh); // Schließen der Datei fclose(fh); // Schließen der Datei
@ -796,7 +796,7 @@ void doSomethingWithAFile(const std::string& filename)
} // Die Datei wird automatisch vom Destruktor geschlossen. } // Die Datei wird automatisch vom Destruktor geschlossen.
// Diese Vorgehensweise bietet massive Vorteile: // Diese Vorgehensweise bietet massive Vorteile:
// 1. Egal was passiert, die Ressource (das Datei-Handle) wird aufgelöst, // 1. Egal was passiert, die Ressource (das Datei-Handle) wird aufgelöst,
// insofern der Destruktor korrekt beschrieben wurde. Es ist möglich // insofern der Destruktor korrekt beschrieben wurde. Es ist möglich
// zu vergessen das Datei-Handle zu schließen, was zu einem "leak" der // zu vergessen das Datei-Handle zu schließen, was zu einem "leak" der
// entsprechenden Ressource führt. // entsprechenden Ressource führt.
@ -804,13 +804,13 @@ void doSomethingWithAFile(const std::string& filename)
// Der Destruktor wird das Datei-Handle im Hintergrund schließen und der // Der Destruktor wird das Datei-Handle im Hintergrund schließen und der
// Programmierer muss sich darum keinerlei Sorgen machen. // Programmierer muss sich darum keinerlei Sorgen machen.
// 3. Der Code ist "exception sicher". // 3. Der Code ist "exception sicher".
// Egal wo die exception geworfen wird, das Aufäumen wird definitv vollzogen. // Egal wo die exception geworfen wird, das Aufräumen wird definitiv vollzogen.
// Der gesamte idiomatische C++ Code verwendet RAII für alle Ressourcen. // Der gesamte idiomatische C++ Code verwendet RAII für alle Ressourcen.
// Weitere Beispiele: // Weitere Beispiele:
// - Speicher verwenden "unique_ptr" und "shared_ptr". // - Speicher verwenden "unique_ptr" und "shared_ptr".
// - Container - verkettete Listen (linked list), vector (selbst organisierende // - Container - verkettete Listen (linked list), vector (selbst organisierende
// Arrays), hash maps, etc., entfernen deren Inhalt, wenn diese außerhalb des // Arrays), hash maps, etc., entfernen deren Inhalt, wenn diese außerhalb des
// Gültigkeitsbereichs laufen. // Gültigkeitsbereichs laufen.
// - Mutex´s verwenden lock_guard und unique_lock. // - Mutex´s verwenden lock_guard und unique_lock.
@ -818,7 +818,7 @@ void doSomethingWithAFile(const std::string& filename)
// Container // Container
///////////////////// /////////////////////
// Die Container der Standard Tenplate Bibliothek beinhaltet einige vordefinierter templates. // Die Container der Standard template Bibliothek beinhaltet einige vordefinierter templates.
// Diese verwalten die Speicherbereiche für die eigenen Elemente und stellen Member-Funktionen // Diese verwalten die Speicherbereiche für die eigenen Elemente und stellen Member-Funktionen
// für den Zugriff und die Maniplulation bereit. // für den Zugriff und die Maniplulation bereit.
@ -842,7 +842,7 @@ for (int i = 0; i < my_vector.size(); i++)
// Oder die Verwendung von Iteratoren: // Oder die Verwendung von Iteratoren:
vector<string>::iterator it; // Initialisierng des Iterators. vector<string>::iterator it; // Initialisierng des Iterators.
for (it = my_vector.begin(); it != my_vector.end(); ++it) for (it = my_vector.begin(); it != my_vector.end(); ++it)
{ {
cout << *it << endl; cout << *it << endl;
} }
@ -861,13 +861,13 @@ ST.insert(30); // Einfügen des Werts 30 in das Set ST
// 10 20 30 // 10 20 30
// Entfernen eines Elements: // Entfernen eines Elements:
ST.erase(20); ST.erase(20);
// Set ST: 10 30 // Set ST: 10 30
// Für das iterieren verwenden wir Iteratoren: // Für das iterieren verwenden wir Iteratoren:
set<int>::iterator it; set<int>::iterator it;
for(it=ST.begin();it<ST.end();it++) for(it=ST.begin();it<ST.end();it++)
{ {
cout << *it << endl; cout << *it << endl;
} }
@ -876,7 +876,7 @@ for(it=ST.begin();it<ST.end();it++)
// 10 // 10
// 30 // 30
// Zum leeren des gesmten Container wird die Methode // Zum leeren des gesamten Container wird die Methode
// Container._name.clear() verwendet. // Container._name.clear() verwendet.
ST.clear(); ST.clear();
cout << ST.size(); // Ausgabe der Set-Größe cout << ST.size(); // Ausgabe der Set-Größe
@ -885,7 +885,7 @@ cout << ST.size(); // Ausgabe der Set-Größe
// Bemerkung: für mehrdeutige Elemente werden multisets verwendet. // Bemerkung: für mehrdeutige Elemente werden multisets verwendet.
// Für hash-Sets sollten unordered_set´s verwendet werden, da diese // Für hash-Sets sollten unordered_set´s verwendet werden, da diese
// wesentlich effizienter sind, allerdings keiner Ordnung folgen. // wesentlich effizienter sind, allerdings keiner Ordnung folgen.
// Verfügbar sind diese Features ab C++11. // Verfügbar sind diese Features ab C++11.
// Map // Map
@ -899,7 +899,7 @@ mymap.insert(pair<char,int>('A',1)); // Einfügen des Werts "1" für den Key "A"
mymap.insert(pair<char,int>('Z',26)); // Einfügen des Werts "26" für den Key "Z". mymap.insert(pair<char,int>('Z',26)); // Einfügen des Werts "26" für den Key "Z".
// Das Iterieren über Maps: // Das Iterieren über Maps:
map<char,int>::iterator it; map<char,int>::iterator it;
for (it=mymap.begin(); it!=mymap.end(); ++it) for (it=mymap.begin(); it!=mymap.end(); ++it)
std::cout << it->first << "->" << it->second << '\n'; std::cout << it->first << "->" << it->second << '\n';
@ -918,25 +918,25 @@ cout << it->second;
// sind effizienter und benötigen keine Reihenfolge. "unordered_maps" sind ab // sind effizienter und benötigen keine Reihenfolge. "unordered_maps" sind ab
// C++11 verfügbar. // C++11 verfügbar.
// Container für nicht-primitve Datentypen benötigen Vergleichsfunktionen im Objekt selbst, // Container für nicht-primitive Datentypen benötigen Vergleichsfunktionen im Objekt selbst,
// oder als Funktionspointer. Primitive Datentypen besitzen default-Vergleichsfunktionen. // oder als Funktionspointer. Primitive Datentypen besitzen default-Vergleichsfunktionen.
// Allerdings können diese überschrieben werden. // Allerdings können diese überschrieben werden.
class Foo class Foo
{ {
public: public:
int j; int j;
Foo(int a) : j(a) {} Foo(int a) : j(a) {}
}; };
struct compareFunction struct compareFunction
{ {
bool operator()(const Foo& a, const Foo& b) const bool operator()(const Foo& a, const Foo& b) const
{ {
return a.j < b.j; return a.j < b.j;
} }
}; };
// Folgender Code ist nicht valide, könnte aber von einigen Compilern // Folgender Code ist nicht valide, könnte aber von einigen Compilern
// als valide angesehen werden: // als valide angesehen werden:
// std::map<Foo, int> fooMap; // std::map<Foo, int> fooMap;
std::map<Foo, int, compareFunction> fooMap; std::map<Foo, int, compareFunction> fooMap;
@ -949,10 +949,10 @@ fooMap.find(Foo(1)); // Wahr
/////////////////////////////////////// ///////////////////////////////////////
// Lambdas sind eine gängige Methodik um anonyme Funktionen an dem // Lambdas sind eine gängige Methodik um anonyme Funktionen an dem
// Ort der Verwendung zu definieren. Darüber hinaus auch bei der // Ort der Verwendung zu definieren. Darüber hinaus auch bei der
// Verwendung von Funktionen als Argument einer Funktion. // Verwendung von Funktionen als Argument einer Funktion.
// Nehmen wir an es soll ein Vektor von "pairs" (Paaren) mithilfe // Nehmen wir an es soll ein Vektor von "pairs" (Paaren) mithilfe
// des zweiten Werts des "pairs" sortiert werden. // des zweiten Werts des "pairs" sortiert werden.
vector<pair<int, int> > tester; vector<pair<int, int> > tester;
@ -968,19 +968,19 @@ sort(tester.begin(), tester.end(), [](const pair<int, int>& lhs, const pair<int,
// Beachte den Syntax von Lambda-Ausdrücken. // Beachte den Syntax von Lambda-Ausdrücken.
// Die [] im Lambda Ausdruck werden für die Variablen verwendet. // Die [] im Lambda Ausdruck werden für die Variablen verwendet.
// Diese so genannte "Capture List" definiert, was außerhalb des Lambdas // Diese so genannte "capture list" definiert, was außerhalb des Lambdas,
// innerhalb der Funktion verfügbar sein soll und in welcher Form. // innerhalb der Funktion verfügbar sein soll und in welcher Form.
// Dies kann folgendes sein: // Dies kann folgendes sein:
// 1. ein Wert [x] // 1. ein Wert [x]
// 2. eine Referenz [&x] // 2. eine Referenz [&x]
// 3. eine beliebige Variable, welche sich im Gültigkeitsbereich durch // 3. eine beliebige Variable, welche sich im Gültigkeitsbereich durch
// die Referenz [&] befindet. // die Referenz [&] befindet.
// 4. wie bei 3. aber mithilfe des Werts [=] // 4. wie bei 3. aber mithilfe des Werts [=]
// Beispiel: // Beispiel:
vector<int> dog_ids; vector<int> dog_ids;
for(int i = 0; i < 3; i++) for(int i = 0; i < 3; i++)
{ {
dog_ids.push_back(i); dog_ids.push_back(i);
} }
@ -1013,8 +1013,7 @@ for(int elem: arr)
} }
// Insofern "auto" verwendet wird, muss der Typ nicht weiter beachtet werden. // Insofern "auto" verwendet wird, muss der Typ nicht weiter beachtet werden.
for(auto elem: arr)
for(auto elem: arr)
{ {
// Anweisungen ... // Anweisungen ...
} }
@ -1029,18 +1028,17 @@ for(auto elem: arr)
// C++ ist eine der Sprachen, bei der es ein leichtes ist sich selbst ins Bein zu schießen. // C++ ist eine der Sprachen, bei der es ein leichtes ist sich selbst ins Bein zu schießen.
// Private-Methoden können überschrieben werden // Private-Methoden können überschrieben werden
class Foo class Foo
{ {
virtual void bar(); virtual void bar();
}; };
class FooSub : public Foo class FooSub : public Foo
{ {
virtual void bar(); // Überschreibt Foo::bar! virtual void bar(); // Überschreibt Foo::bar!
}; };
// 0 == false == NULL
// 0 == false == NULL
bool* pt = new bool; bool* pt = new bool;
*pt = 0; // Setzt den Wert des Pointers 'pt' auf false. *pt = 0; // Setzt den Wert des Pointers 'pt' auf false.
pt = 0; // Setzt 'pt' auf den "null-pointer". Keine Compiler-Warnung. pt = 0; // Setzt 'pt' auf den "null-pointer". Keine Compiler-Warnung.
@ -1050,18 +1048,17 @@ int* pt2 = new int;
*pt2 = nullptr; // Kompiliert nicht. *pt2 = nullptr; // Kompiliert nicht.
pt2 = nullptr; // Setzt pt2 auf null. pt2 = nullptr; // Setzt pt2 auf null.
// Eine Ausnahme bilden bools. // Eine Ausnahme bilden bool´s.
// Dies erlaubt es "null-pointer" zu testen: if(!ptr) // Dies erlaubt es "null-pointer" zu testen: if(!ptr)
// Die Konsequenz ist jedoch, dass dem nullptr ein bool zugewiesen werden kann. // Die Konsequenz ist jedoch, dass dem nullptr ein bool zugewiesen werden kann.
*pt = nullptr; // Kompiliert auch wenn '*pt' ein bool ist! *pt = nullptr; // Kompiliert auch, wenn '*pt' ein bool ist!
// '=' != '=' != '='! // '=' != '=' != '='!
// Ruft Foo::Foo(const Foo&) auf, oder den Kopierkonstruktor // Ruft Foo::Foo(const Foo&) auf, oder den Kopierkonstruktor
Foo f2; Foo f2;
Foo f1 = f2; Foo f1 = f2;
// Ruft Foo::Foo(const Foo&) auf, aber kopiert lediglich den "Foo" Teil von // Ruft Foo::Foo(const Foo&) auf, aber kopiert lediglich den "Foo" Teil von
// "fooSub". Alle zusätzlichen Member werden verworfen. Diese eigenartige Verhalten // "fooSub". Alle zusätzlichen Member werden verworfen. Diese eigenartige Verhalten
// wird auch "object slicing" genannt. // wird auch "object slicing" genannt.
FooSub fooSub; FooSub fooSub;
@ -1077,10 +1074,10 @@ f1 = f2;
#include<tuple> #include<tuple>
// Konzeptionell sind Tuples alten Datenstrukturen sehr ähnlich, allerdings haben diese keine // Konzeptionell sind Tuple´s alten Datenstrukturen sehr ähnlich, allerdings haben diese keine
// benamten Daten-Member, sondern werden durch die Reihenfolge angesprochen. // bezeichneten Daten-Member, sondern werden durch die Reihenfolge angesprochen.
// Erstellen des Tuples und das Einfügen eines Werts. // Erstellen des Tuples und das Einfügen eines Werts.
auto first = make_tuple(10, 'A'); auto first = make_tuple(10, 'A');
const int maxN = 1e9; const int maxN = 1e9;
const int maxL = 15; const int maxL = 15;
@ -1122,8 +1119,7 @@ cout << get<5>(concatenated_tuple) << "\n"; // Ausgabe: 'A'
// Die meisten Operatoren in C++ entsprechen denen aus anderen Sprachen // Die meisten Operatoren in C++ entsprechen denen aus anderen Sprachen
// Logische Operatoren. // Logische Operatoren.
// C++ verwendet so genannte "Short-circuit" Evaluierung für Boolean-Ausdrücke.
// C++ verwendet so genannte "Short-circuit" Evaluierung für boolean-Ausdrücke.
// Das zweite Argument wird ausgeführt bzw. evaluiert, wenn das erste Argument genügt, // Das zweite Argument wird ausgeführt bzw. evaluiert, wenn das erste Argument genügt,
// um den Ausdruck zu bestimmen. // um den Ausdruck zu bestimmen.