Strukturen und Klassen Flashcards

1
Q

Was machen Structs?

A

Sie gruppieren Variablen bzw. Werte mit gleicher “Struktur”, sprich sie erstellen einen neuen Typ.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Was ist der formale Wertebereich eines Structs?

A

Der formale Wertebereich eines Structs setzt sich aus dem kartesischen Produkt der Wertebereiche der bereits existierenden Typen zusammen, die für die Erstellung des Structs verwendet wurden.
Will man also z.B. einen neuen Typ für rationale Zahlen mit einem Struct generieren, so ist der Wertebereich des neuen Typs 𝚛𝚊𝚝 gegeben durch 𝚒𝚗𝚝 × 𝚒𝚗𝚝, da zur Erstellung von rationalen Zahlen x/y zwei ganze Zahlen x und y gebraucht werden.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Was sind Member-Variablen eines Structs?

A

Die Member-Variablen sind “Untertypen” eines Structs, sprich in einem Struct definierte Variablen mit einem Typ. Wollen wir z.B. eine neues Struct 𝚖𝚘𝚟𝚒𝚎 erstellen…

𝚜𝚝𝚛𝚞𝚌𝚝 𝚖𝚘𝚟𝚒𝚎 {
  𝚌𝚑𝚊𝚛 𝚝𝚒𝚝𝚕𝚎;
  𝚌𝚑𝚊𝚛 𝚍𝚒𝚛𝚎𝚌𝚝𝚘𝚛;
  𝚒𝚗𝚝 𝚛𝚎𝚕𝚎𝚊𝚜𝚎𝚢𝚎𝚊𝚛;
}

…, so sind die einzelnen Elemente des Structs, z.B. 𝚌𝚑𝚊𝚛 𝚝𝚒𝚝𝚕𝚎, die Member-Variablen.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Wie kann man auf die einzelnen Member-Variablen eines Structs zugreifen? Wie würde eine Funktion 𝚊𝚍𝚍 für die Addition zweier Werte des Typs 𝚛𝚊𝚝 (rationale Zahlen, in einem Struct definiert) aussehen?

A

Zuerst definieren wir die rationalen Zahlen durch zwei Werte des Typs 𝚒𝚗𝚝, wobei 𝚗 der Zähler (“Nominator”) und 𝚍 der Nenner (“Denominator”) ist.

𝚜𝚝𝚛𝚞𝚌𝚝 𝚛𝚊𝚝 {
𝚒𝚗𝚝 𝚗;
𝚒𝚗𝚝 𝚍;
}

Um auf die einzelnen Member-Variablen zuzugreifen, brauchen wir den Punkt “.” (ähnlich wie bei Vektoren). Eine Funktion zur Addition rationaler Zahlen würde also wie folgt aussehen:

𝚛𝚊𝚝 𝚊𝚍𝚍 (𝚌𝚘𝚗𝚜𝚝 𝚛𝚊𝚝 𝚊, 𝚌𝚘𝚗𝚜𝚝 𝚛𝚊𝚝 𝚋) {
  𝚛𝚊𝚝 𝚛𝚎𝚜𝚞𝚕𝚝;
  𝚛𝚎𝚜𝚞𝚕𝚝.𝚗 = 𝚊.𝚗 * 𝚋.𝚍 + 𝚊.𝚍 * 𝚋.𝚗;
  𝚛𝚎𝚜𝚞𝚕𝚝.𝚍 = 𝚊.𝚍 * 𝚋.𝚍;
  𝚛𝚎𝚝𝚞𝚛𝚗 𝚛𝚎𝚜𝚞𝚕𝚝;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Wie werden Structs initialisiert?

A

Wird ein Struct initialisiert, so werden alle Member-Variablen des Structs entsprechend ihrer Typen default-initialisiert. Für Member-Variablen fundamentaler Typen passiert dabei nichts und der Wert bleibt undefiniert.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Sei 𝚜𝚝𝚛𝚞𝚌𝚝 𝚗𝚎𝚠𝚝𝚢𝚙𝚎 ein Struct und
𝚗𝚎𝚠𝚝𝚢𝚙𝚎 𝚜, 𝚝;
die Initialisierung zweier Variablen vom Typ 𝚗𝚎𝚠𝚝𝚢𝚙𝚎. Was passiert bei der Zuweisung 𝚜 = 𝚝; ?

A

Den Member-Variablen von t werden die Werte der Member-Variablen von s zugewiesen.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Weshalb funktionieren die Vergleichsoperatoren nur für fundamentale Typen, nicht aber für Structs?

A

Da der Vergleich memberweise passiert und dies für die meisten Structs wenig Sinn machen würde, z.B. bei den rationalen Zahlen mit Struct-Typ 𝚛𝚊𝚝 würde der Vergleich 2/4 = 4/8 als falsch ausgewertet.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Was ist die Signatur einer Funktion und wie ist es dadurch möglich, mehrere Funktion mit gleichem Namen zu definieren?

A

Eine Funktion ist bestimmt durch Namen, Typen, Anzahl und Reihenfolge der Argumente. Sind zwei Funktionen mit gleichem Namen vorhanden, wählt der Compiler beim Aufruf der Funktion automatisch diejenige, die aufgrund der Signatur “am besten passt”.

Beispiel:
Gegeben seien zwei Funktionen:
f₁: 𝚒𝚗𝚝 𝚙𝚘𝚠 (𝚒𝚗𝚝 𝚋, 𝚒𝚗𝚝 𝚎) {…}
f₂: 𝚒𝚗𝚝 𝚙𝚘𝚠 (𝚒𝚗𝚝 𝚎) {𝚛𝚎𝚝𝚞𝚛𝚗 𝚙𝚘𝚠(𝟸, 𝚎); }
Der Compiler entscheidet sich...
𝚜𝚝𝚍::𝚌𝚘𝚞𝚝 << 𝚙𝚘𝚠(𝟹,𝟹); … für f₁;
𝚜𝚝𝚍::𝚌𝚘𝚞𝚝 << 𝚙𝚘𝚠(𝟹); … für f₂.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Was sind Operatoren und was bedeutet es, einen Operator zu überladen?

A

Operatoren sind spezielle (fundamentale) Funktionen wie +, -, *, /, +=, usw. .
Einen Operator zu überladen, heisst, ihn anders zu definieren, als er ursprünglich definiert worden ist.
Wir können z.B. den Operator “+” durch ein “/” überladen, so dass gilt: 4 + 2 = 2.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Wann ist es sinnvoll, Operatoren zu überladen?

A

Wenn sie für ein Struct nicht bzw. anders definiert sind, als sie eigentlich müssten.
(z.B. beim Struct der rationalen Zahlen braucht es Änderungen an den Operatoren, da ansonsten die Operationen nicht funktionieren.)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Betrachte folgende Überladung des Operators “+=” im Struct für rationale Zahlen:

𝚛𝚊𝚝 𝚘𝚙𝚎𝚛𝚊𝚝𝚘𝚛+= (𝚛𝚊𝚝 𝚊, 𝚛𝚊𝚝 𝚋) 
{
    𝚊.𝚗 = 𝚊.𝚗 * 𝚋.𝚍 + 𝚊.𝚍 * 𝚋.𝚗; 
    𝚊.𝚍 *= 𝚋.𝚍; 
    𝚛𝚎𝚝𝚞𝚛𝚗 𝚊; 
}

Weshalb funktioniert dieser Code nicht und wie könnte man ihn verbessern?

A

Der Ausdruck 𝚛 += 𝚜 hat zwar den gewünschten Wert, weil die Aufrufargumente R-Werte sind, jedoch nicht den gewünschten Effekt der Veränderung von 𝚛. Zudem stellt 𝚛 += 𝚜 entgegen der eigentlichen Konvention von C++ keinen L-Wert dar.

Man muss also das auszugebende Resultat als L-Wert deklarieren, sprich:
𝚛𝚊𝚝&amp; 𝚘𝚙𝚎𝚛𝚊𝚝𝚘𝚛+= (𝚛𝚊𝚝&amp; 𝚊, 𝚛𝚊𝚝 𝚋) 
{
    𝚊.𝚗 = 𝚊.𝚗 * 𝚋.𝚍 + 𝚊.𝚍 * 𝚋.𝚗; 
    𝚊.𝚍 *= 𝚋.𝚍; 
    𝚛𝚎𝚝𝚞𝚛𝚗 𝚊; 
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Welche Operatoren kann man neben arithmetischen Operatoren auch noch überladen? Wozu ist dies nützlich?

A

Man kann ebenso Ein- und Ausgabeoperatoren überladen, falls man eine konkretere Ausgabe erhalten möchte bzw. von einer allgemeineren Eingabe lesen möchte.

Beispiel:
Im Fall des Structs der rationalen Zahlen sei die Eingabe definiert als:
𝚜𝚝𝚍::𝚒𝚜𝚝𝚛𝚎𝚊𝚖& 𝚘𝚙𝚎𝚛𝚊𝚝𝚘𝚛» (𝚜𝚝𝚍::𝚒𝚜𝚝𝚛𝚎𝚊𝚖& 𝚒𝚗, 𝚛𝚊𝚝& 𝚛) {
𝚌𝚑𝚊𝚛 𝚌;
𝚛𝚎𝚝𝚞𝚛𝚗 𝚒𝚗&raquo_space; 𝚛.𝚗&raquo_space; 𝚌&raquo_space; 𝚛.𝚍;
}
Hierbei ist c der separierende Charakter ‘/’. Das Programm liest also ein 𝚛 aus dem Eingabestrom und gibt diesen als L-Wert zurück.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Betrachten wir ein Struct für rationale Zahlen 𝚛𝚊𝚝.

Wie würden wir vorgehen, wenn wir dies in eine Bibliothek bringen wollen?

A

Die Definition des Structs sowie die Deklarationen aller Funktionen kommt in die Header-Datei 𝚛𝚊𝚝.𝚑,
die arithmetischen Operatoren, die relationalen Operatoren sowie die Ein-/Ausgabe-Operatoren gehören in die Programmdatei 𝚛𝚊𝚝.𝚌𝚙𝚙.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Was sind Klassen und wozu braucht man sie?

A

Klassen sind Varianten von Structs, die eine sog. Datenkapselung in C++ ermöglichen. Bei Structs werden den Member-Variablen öffentlicher Zugriff gewährt, wobei sie bei Klassen jedoch privat sind, d.h. nicht sichtbar. Man kann in Klassen jedoch weitere Unterteilungen in 𝚙𝚞𝚋𝚕𝚒𝚌 und 𝚙𝚛𝚒𝚟𝚊𝚝𝚎 machen, um so gewisse Teile noch öffentlich sichtbar zu lassen.
Somit ist es eigentlich nur das Default-Setting, das bei Klassen (privat) und Strukturen (public) anders ist.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Was ist eine Memberfunktion?

A

Eine Memberfunktion ist eine Funktion, die auf Membervariablen zugreift und diese ändert.

Beispiel:
Sei eine Klasse 𝚊𝚞𝚝𝚘 gegeben:

𝚌𝚕𝚊𝚜𝚜 𝚊𝚞𝚝𝚘 {
𝚞𝚗𝚜𝚒𝚐𝚗𝚎𝚍 𝚒𝚗𝚝 𝙿𝚛𝚎𝚒𝚜;
𝚜𝚝𝚍::𝚜𝚝𝚛𝚒𝚗𝚐 𝙼𝚊𝚛𝚔𝚎;
𝚜𝚝𝚍::𝚜𝚝𝚛𝚒𝚗𝚐 𝙱𝚎𝚜𝚒𝚝𝚣𝚎𝚛;

𝚟𝚘𝚒𝚍 𝚅𝚎𝚛𝚔𝚊𝚞𝚏(𝚜𝚝𝚍::𝚜𝚝𝚛𝚒𝚗𝚐 𝙱𝚎𝚜𝚒𝚝𝚣𝚎𝚛_𝚗𝚎𝚞) {
𝙱𝚎𝚜𝚒𝚝𝚣𝚎𝚛 = 𝙱𝚎𝚜𝚒𝚝𝚣𝚎𝚛_𝚗𝚎𝚞;
}
}

Die Funktion 𝚅𝚎𝚛𝚔𝚊𝚞𝚏 ändert den Besitzer des Autos, greift also auf eine Membervariable zu und ändert diese.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Was ist der Unterschied zwischen 𝚙𝚞𝚋𝚕𝚒𝚌 und 𝚙𝚛𝚒𝚟𝚊𝚝𝚎 in Klassen? Wie wirkt sich dies auf Funktionen

A

Der Hauptunterschied zwischen 𝚙𝚞𝚋𝚕𝚒𝚌 und 𝚙𝚛𝚒𝚟𝚊𝚝𝚎 liegt darin, von wo aus man auf die Eigenschaften der Klasse zugreifen kann.
Bei 𝚙𝚛𝚒𝚟𝚊𝚝𝚎 kann auf Funktionen, Eigenschaften, etc. nur innerhalb der Klasse zugegriffen werden. Dabei ist es egal, ob der Zugriff vom 𝚙𝚛𝚒𝚟𝚊𝚝𝚎-Teil oder vom 𝚙𝚞𝚋𝚕𝚒𝚌-Teil aus geschieht. Wird jedoch von ausserhalb der Klasse (z.B. in der main-Funktion) auf den 𝚙𝚛𝚒𝚟𝚊𝚝𝚎-Teil zugegriffen, so gibt das Programm einen Fehler aus. Dies ist anders bei 𝚙𝚞𝚋𝚕𝚒𝚌, hier kann von überall aus auf die Klasse zugegriffen werden.

17
Q

Was sind Konstruktoren?

A

Konstruktoren sind spezielle Memberfunktionen einer Klasse, die den Namen der Klasse tragen. Sie können überladen werden und werden bei der Variablendeklaration wie eine Funktion aufgerufen.
Ein Konstruktor kann als Vorschrift angesehen werden, die erfüllt sein muss, damit ein Element einer Klasse “gebaut” werden darf.

Beispiel:
Deklarieren wir die Klasse 𝚊𝚞𝚝𝚘 mit einem Konstruktor wie folgt,…

𝚊𝚞𝚝𝚘(𝚜𝚝𝚍::𝚜𝚝𝚛𝚒𝚗𝚐 𝙼𝚊𝚛𝚔𝚎, 𝚒𝚗𝚝 𝙿𝚛𝚎𝚒𝚜)

… so müssen in der main-Funktion beim Deklarieren eines Wertes der Auto-Klasse beide Variablen in dieser Reihenfolge verwendet werden, sprich:

𝚊𝚞𝚝𝚘 𝙺𝚊𝚎𝚏𝚎𝚛(𝚅𝚘𝚕𝚔𝚜𝚠𝚊𝚐𝚎𝚗, 𝟹0000) wäre gültig.
𝚊𝚞𝚝𝚘 𝙺𝚊𝚎𝚏𝚎𝚛(𝚅𝚘𝚕𝚔𝚜𝚠𝚊𝚐𝚎𝚗) oder 𝚊𝚞𝚝𝚘 𝙺𝚊𝚎𝚏𝚎𝚛() wäre hingegen ungültig.

18
Q

Wie können Konstruktoren aufgerufen werden?

A

Konstruktoren können direkt und indirekt aufgerufen werden:

Für den Konstruktor
𝚊𝚞𝚝𝚘(𝚜𝚝𝚍::𝚜𝚝𝚛𝚒𝚗𝚐 𝙼𝚊𝚛𝚔𝚎, 𝚒𝚗𝚝 𝙿𝚛𝚎𝚒𝚜):

Direkt, z.B.:
𝚊𝚞𝚝𝚘 𝙺𝚊𝚎𝚏𝚎𝚛(𝚅𝚘𝚕𝚔𝚜𝚠𝚊𝚐𝚎𝚗, 𝟹0000)
Indirekt, z.B.:
𝚊𝚞𝚝𝚘 𝙺𝚊𝚎𝚏𝚎𝚛 = 𝚊𝚞𝚝𝚘(𝚅𝚘𝚕𝚔𝚜𝚠𝚊𝚐𝚎𝚗, 𝟹0000)

19
Q

Was macht der Default-Konstruktor und wozu braucht es ihn?

A

Der Default-Konstruktor wird automatisch aufgerufen bei Deklarationen der Form 𝚌𝚕𝚊𝚜𝚜𝚗𝚊𝚖𝚎 𝙾𝚋𝚓𝚎𝚌𝚝𝙽𝚊𝚖𝚎, z.B. 𝚊𝚞𝚝𝚘 𝙺𝚊𝚎𝚏𝚎𝚛.
Es ist der eindeutige Konstruktor mit leerer Argumentliste, der die Member-Variablen initialisiert.
Er muss existieren, wenn 𝚊𝚞𝚝𝚘 𝙺𝚊𝚎𝚏𝚎𝚛 kompilieren soll.
Werden in einem Struct keine Konstruktoren verwendet, so wird ein Default-Konstruktor automatisch erzeugt.

20
Q

Was bedeutet es, Typen zu kapseln, und wozu ist dies gut?

A

Man kapselt Typen, um eigene Typen zur Verfügung zu stellen. Dies kann z.B. zur Erweiterung des Wertebereichs gewisser Typen nützlich sein. Als

Beispiel: der Typ 𝚒𝚗𝚝 stellt uns zu wenig zur Verfügung, also definieren wir:
𝚞𝚜𝚒𝚗𝚐 𝚒𝚗𝚝𝚎𝚐𝚎𝚛 = 𝚕𝚘𝚗𝚐 𝚒𝚗𝚝;*

*𝚕𝚘𝚗𝚐 ist eine allgemeine Erweiterung des Wertebereichs (mind. 32 Bits).