Upload
others
View
11
Download
1
Embed Size (px)
Citation preview
Einführung in objektorientiertes Pro-grammieren in C++Karl Gmeiner
2015
Einführung in objektorientiertes Programmieren in C++
1 Programmierparadigmen
• Programmieren = Problemstellung in einem Computerprogramm umsetzen.
– Problemstellung wird in Einheiten untergliedert.– Programmierparadigma: Art der Einheit = Grundlegende Art, wie programmiert wird.
• Einige Paradigmen:
– Imperatives Programmieren
* Prozedurales Programmieren (C)* Objektorientieres Programmieren (Java, C++)
– Deklaratives Programmieren
* Funktionales Programmieren (OCaml)* Logisches Programmieren (tw. SQL)
• Imperatives strukturiertes Programmieren: Programmfluss durch vorgegebene Konstrukte
– Sequenzen, Iterationen, Bedingungen, Abstraktionen
2 Objektorientiertes Programmieren
• Gliederung des Programmes in Objekte
2.1 Objekte
• Haben Eigenschaften
– Bestehen selbst aus weiteren Objekten
• Haben ein Verhalten
– Kommunizieren mit anderen Objekten
3 Objekt Pluto
• Eigenschaften:
– Name: “Pluto”
• Verhalten:
– Pluto kann bellen– Sieht Pluto einen anderen Hund, so wedelt er mit dem Schwanz
4 Objekt Idefix
• Eigenschaften:
– Name: “Idefix”
• Verhalten:
– Idefix kann bellen– Sieht Idexfix einen anderen Hund, so wedelt er mit dem Schwanz
1
Einführung in objektorientiertes Programmieren in C++
Figure 1: Pluto
5 Allgemein Hunde
• Eigenschaften:
– Hunde haben Namen
• Verhalten:
– Hunde können bellen– Sehen Hunde einen anderen Hund, wedeln sie mit dem Schwanz
2
Einführung in objektorientiertes Programmieren in C++
Figure 2: Idefix
3
Einführung in objektorientiertes Programmieren in C++
4
Einführung in objektorientiertes Programmieren in C++
5
Einführung in objektorientiertes Programmieren in C++
5.1 Was ist der Unterschied zwischen “Hund” und “Pluto”?
• Hund = Beschreibung einer Art (“Klassifikation”)• Pluto ist eine Instanz der Klasse Hund.• Beschreibung von “Hund” erklärt, wie sich einzelne Hunde verhalten und welche Eigen-
schaften sie haben.
6 Klassen
• Objekte werden in vielen Programmiersprachen durch eine entsprechende Klassifikation (=Klasse) beschrieben.
– Beispiele: C++, Java, C#, . . .
• Sichtbarkeiten
– Implementierung von Verhalten sollte versteckt sein (Austauschbarkeit)– Eigenschaften sollten nicht direkt manipuliert werden können (Data-Hiding)
6
Einführung in objektorientiertes Programmieren in C++
7 Dog-Klasse (1. Entwurf)
// dog.h
class Dog{public:
void talk(); // Methodevoid meet(Dog other); // Methodestring name; // Membervariablebool tailWagging; // Membervariable
}
• VORSICHT: Code hat VIELE Probleme!
8 Implementierung
// dog.cppvoid Dog::talk() {
cout << name << " says wuff" << endl;}
void Dog::meet(Dog other) {this->tailWagging = true;other.tailWagging = true;cout << name << " and " << other.name
<< " wag their tails" << endl;}
Innerhalb eines Objekts ist this ein Pointer (daher ->) auf das Objekt.
9 Verwenden von Objekten
// main.cppint main() {
Dog pluto;Dog odie;pluto.name = "Pluto";odie.name = "Odie";pluto.talk();// does 'Dog::talk();' work?
odie.talk();pluto.meet(odie);
pluto.tailWagging = false;}
7
Einführung in objektorientiertes Programmieren in C++
10 Funktionsaufrufe mit Objekten - Call-by-value
• Call-by-value
void changeName(Dog d) {d.name = "odie";
}
int main() {Dog pluto;pluto.name = "pluto";changeName(pluto);cout << pluto.name << endl; // Ausgabe?return 0;
}
11 Funktionsaufruf mit Objekten - Call-by-reference
void changeName(Dog &d) {d.name = "odie";
}
int main() {Dog pluto;pluto.name = "pluto";changeName(pluto);cout << pluto.name << endl; // Ausgabe?return 0;
}
• Referenz mit const: Objekt kann nicht geändert werden.• Vorsicht: C# und Java benutzen immer Call-by-reference!
– Grund: Objekte können gross werden– Kopieren kostet viel Zeit.
12 Data-Hiding
• Entscheidungsfreiheit: Es ist die Entscheidung des Hundes, ob er mit dem Schwanz wedeltoder nicht!
• tailWagging sollte daher nicht nicht von aussen gesetzt werden können.• Gleiches für name
13 Dog-Klasse (2. Entwurf)
// dog.hclass Dog{private:
8
Einführung in objektorientiertes Programmieren in C++
string name;bool tailWagging;
public:void talk();void meet(Dog &other);
}
14 Jetzt brauchen wir Getter und Setter, oder?
15 Getter and Setter are evil! (c) Karl Gmeiner
15.1 Warum objektorientiertes Programmieren?
• Objekte ergänzen reine Datenpakete (structs) um Verhalten, welches die Daten im Objektmanipuliert
• Daten werden von aussen geschützt.
– Zuverlässigkeit und Austauschbarkeit (Beispiel: Array in Objekt kann durch Liste ersetztwerden)
– Grundsatz: Die Klasse weiss immer noch am besten, wie man mit den Daten darinumgeht.
• Zusätzliche Abstraktionsebene entspricht Erfahrung in echter Welt
Verwenden von Getter und Setter = Degradieren einer Klasse zu einem reinen Datenpaket mitkomplexer Syntax.
16 XY sagte, wir brauchen Getter und Setter.
Ok, dann ist das aber kein Objekt sondern ein Datenpaket.
16.1 Aber manchmal brauche ich doch zumindest ein get?
• Ja. Und?• Grundsatz: Wenn ich es nicht brauche, sollte ich es nicht machen.• “Feature” “Generate Getters and Setters” ist wirklich böse und reduziert Wartbarkeit des
Codes.
16.2 Warum machen es dann viele?
Weil viele, die heute Programmieren unterrichten, mit structs gross geworden sind und diesegewohnt sind.
16.3 Ist jemand, der immer Getter und Setter erstellt, ein schlechter Pro-grammierer?
Nein. Er programmiert nur in einem nicht-objektorientieren Stil.
9
Einführung in objektorientiertes Programmieren in C++
Figure 3: Getter, Setter
10
Einführung in objektorientiertes Programmieren in C++
17 private-Sichtbarkeit
• Wie greift meet nun auf die Member von other zu?
– Kein Problem. private bezieht sich auf Klasse.– Wie schon gesagt: Die Klasse weiss, wie sie mit ihren Instanzen umgeht!
void Dog::meet(Dog other) {tailWagging = true;
other.tailWagging = true;cout << name << " and " << other.name
<< " wag their tails" << endl;// Zugriff auf others private member ist kein Problem,// weil other eine Instanz von Dog ist.
}
MAN BRAUCHT KEINE get-METHODE UM AUF MEMBERVARIABLEN ANDERER INSTANZENEINER KLASSE INNERHALB DER KLASSE ZUZUGREIFEN!
18 Konstruktoren
• Real world: Wann bekommt ein Hund einen Namen?
– Bei der Geburt.
• Bei Objekten spezielle Methode in Klassen zur Erzeugung von Objekten
// dog.hclass Dog {public:
Dog(string n); // constructor (ctor)
19 Implementierung ctor
• Setzen von Membervariablen
– Entweder im Block– oder davor
// dog.cppDog::Dog(string n) {
name = n;cout << "creating dog " << n << endl;
}
// dog.cppDog::Dog(string n) : name(n) {
cout << "creating dog " << n << endl;}
11
Einführung in objektorientiertes Programmieren in C++
20 Aufruf von Konstruktor
Direkt durch Angabe der Parameter oder mit “=”.
int main() {// Dog dog; not possibleDog pluto("pluto");Dog odie = string("odie");// same as Dog odie(string("odie"));!
// Let's create a twin of pluto:Dog anotherDogNamedPluto = pluto;// Hm, according to what we said above// for odie, this is the same as// Dog anotherDogNamedPluto(pluto);
// But what ctor was called here?return 0;
}
21 Copy-Konstruktor
• C++ erzeugt einige Konstruktoren und Methoden implizit
– Z.B. den Copy-Konstruktor: Dog(const Dog &dog)– Implizit Zuweisung aller Member-Variablen– Durch Explizit-Machen kann Default (Zuweisung aller Member-Variablen) geändert
werden.
// dog.hclass Dog {
/* ... */Dog(const Dog &dog);/* ... */
}
// dog.cppDog::Dog(const Dog &dog) : name(dog.name) {
cout << "creating a twin of " << name << endl;}
22 Destruktoren
• Gegenstück zum Konstruktor: Destruktor
– Wird aufgerufen, wenn Objekt zerstört wird und Speicher freigegeben werden soll
// dog.hclass Dog {public:
/* ... */
12
Einführung in objektorientiertes Programmieren in C++
~Dog(); // destructor (dtor)
// dog.cppDog::~Dog() {
cout << "destroying " << name << " :(" << endl;}
23 Aufruf von Destruktor am Ende des Gültigkeitsbereich
int main() {for(int i = 0; i < 3; ++i) {
Dog pluto("pluto no " + i);pluto.talk();
}return 0;
}
24 Komplexes Beispiel
// main.cppDog makeBarkAndReturn(Dog dog) {
dog.talk();return dog;
}
int main() {Dog pluto("pluto");
for(int i = 0; i < 3; ++i) { Dog other = pluto; }
Dog yetAnother = makeBarkAndReturn(pluto);
return 0;}
25 How to Shoot Yourself In the Foot
25.1 C++
You accidently create a dozen instances of yourself and shoot them all in the foot.
26 Ausgabe
creating dog plutocreating twin dog plutodestroying pluto :(creating twin dog plutodestroying pluto :(
13
Einführung in objektorientiertes Programmieren in C++
creating twin dog plutodestroying pluto :(creating twin dog plutopluto says wuffcreating twin dog plutodestroying pluto :(destroying pluto :(destroying pluto :(
27 const-Methoden
• Ändert eine Methode das Objekt nicht, so sollte man sie als const deklarieren.
// dog.hclass Dog{
/* ... */void talk() const;void meet(Dog &other);
}
• Klassen, bei denen alle Methoden const sind (ausser ctor und dtor) heissen immutable.• Prinzipiell ist es immer erstrebenswert, immutable Klassen zu verwenden.
28 Beispiel
// dog.hclass Dog { /*...*/
void talk() const;void meet(Dog &other);
}
int main() {Dog idefix("idefix");Dog snoopy("snoopy");idefix.meet(snoopy);const Dog & other = idefix;other.talk();// not possible: other.meet(snoopy)// not possible: snoopy.meet(other)return 0;
}
29 Dynamische Speicherverwaltung in C++
29.1 new
• new reserviert (wie malloc) Speicher.• new ruft ctor auf.
14
Einführung in objektorientiertes Programmieren in C++
29.2 delete
• delete gibt Speicher wieder frei• delete ruft dtor auf.
29.3 Arrays
• Mit new type[size] wird ein neues Array angelegt.• Arrays mit delete[] freigeben• In C++ Verwendung von Arrays selten.
29.4 Beispiel
Dog *pluto = new Dog("pluto");/* ... */delete pluto;
30 Zusammenfassung: MyArray, Array für int
// myarray.hclass MyArray {public:
MyArray(int len);MyArray(const MyArray& other);
~MyArray();
void set(int index, int value);int get(int index) const;int length() const;
private:int mLength; // cannot have same name as methodint * data;
}
31 MyArray: Konstruktor 1
MyArray::MyArray(int len) :mLength(len),data(new int[len]) {}
32 MyArray: Methoden
void MyArray::set(int index, int value) {data[index] = value;
}
15
Einführung in objektorientiertes Programmieren in C++
int MyArray::get(int index) const {// don't forget const!return data[index];
}
int MyArray::length() const {return mLength;
}
33 Destruktor
MyArray::~MyArray() {cout << "deleting data" << endl;delete[] data;
}
34 Copy-Constructor nötig?
34.1 Beispiel ohne expliziten Copy-Construktor
int main() {MyArray arr(1); // calls new in ctorarr.set(0, 3); // data[0] = 3
{MyArray arr2 = arr; // copy-ctor// the implicit copy-ctor executes// "arr2.data = arr.data"!
arr2.set(0, 1);// what is arr.get(0)?
} // calls dtor of arr2, deleting arr2.data
arr.set(0, 2); // wait, wasn't arr.data deleted?} // again, deleting data (double delete)
35 Copy-Constructor
MyArray::MyArray(const MyArray & arr) :length(arr.mLength), data(new int[mLength]) {// copy values of array to new arrayfor(int i = 0; i < mLength; ++i) {
// We easily can access data in "arr"// because, remember, private is// relative to the class, not the object!data[i] = arr.data[i];
}}
• Weitere implizite Funktionen sind problematisch (Rule of three)
16
Einführung in objektorientiertes Programmieren in C++
– Destructor, Copy ctor, und– Copy assignment operator (normale Zuweisung [dazu in einer späteren Einheit])– In C++11 rule of 5 wegen “Move Semantic”: Move constructor, Move assignment
operator
36 So viel fürs Erste zu Objekten
• Zusammenfassend
– Klassen sind Beschreibungen, aus denen konkrete Dinge erstellt werden können
* Objekte sind Instanzen von Klassen– Objekte enthalten Membervariablen (Daten) und Methoden (Verhalten)– Objekte werden durch Aufruf eines Konstruktors erstellt und durch den Destruktor
zerstört– Objekte werden oft als Referenzen übergeben, um unnötiges Kopieren zu vermeiden
(sehr oft mit const-Modifier)
17