mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2025-04-27 07:33:57 +00:00
[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:
parent
7fca9b47a9
commit
41f2b7f168
@ -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
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user