Programmieren in C++ Einführung
Inhalt Übersicht über das Modul Einführung in C++ Struktur eines C++-Programms Präprozessor Globale und Modulvariablen Einfache Datentypen Automatische Typinferenz Konstanten und konstante Ausdrücke Vereinheitlichte Initialisierung und Initialisierungslisten (C++11) Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-2
Übersicht Leitidee neuer Standard C++11 Unterschiede zu und Gemeinsamkeiten mit Java aufzeigen praktischer Einsatz von C++ erleben Ablauf 2V1U (1. Teil: H. Veitschegger, 2. Teil: C. Stamm) 4 Übungen mit Testatpflicht: String, JNI, STL Einsatz, STL Erweiterung 2 Klausuren: Di 16.4.13 (14.30-16.00), Di 11.6.13 (14.30-16.00) Erforderliche Vorkenntnisse OO-Programmierung in Java 1.5 oder höher Web (Zeitplan, Unterlagen, Übungen, Literaturliste) http://web.fhnw.ch/plattformen/prcpp Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-3
Literatur Einführung in die Programmierung mit C++. B. Stroustrup. Pearson, 2010. C++11 programmieren: 60 Techniken für guten C++11-Code. T. Will. Galileo Computing, 2012. C++ Primer. Stanley B. Lippman, José Lajoie, Barbara E. Moo, 5th edition, Addison-Wesley, 2012. Modern C++ Design. Andrei Alexandrescu. John Wiley, 2001. Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-4
Einführung in C++ Gemeinsamkeiten mit Java typisierte, objektorientierte Sprache sehr ähnliche Syntax (Java-Syntax wurde an C++ angelehnt) ähnliche Grundtypen, Operatoren und Klassenkonzept Grobe Unterschiede zu Java C++-Programm muss nicht objektorientiert sein Abwärtskompatibilität mit C mehrere Klassenhierarchien möglich plattformabhängiger Maschinencode anstatt Bytecode für die VM hohe Performanz, weil Programm auf dem Prozessor direkt abläuft C++-Programme können aufs unterliegende System zugreifen sehr hohe Flexibilität (fast alles ist machbar!) hohe Plattformabhängigkeit Flexibleres Speichermanagement Speicheradressen sind sichtbar und können manipuliert werden kein integrierter Garbage Collector, dafür Smart-Pointers, d.h. nicht mehr benötigte Objekte und Arrays werden meistens automatisch gelöscht Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-5
Grobe Unterschiede zu Java (Forts.) Flexiblerer Polymorphismus Methoden können bei Bedarf polymorph (virtual) sein Operatoren dürfen überladen werden Mehrfachvererbung ist auch für Klassen erlaubt Effizienz vor Sicherheit keine Laufzeit-Checks bei Arrayzugriffen Arrays und Objekte können auch auf dem Stack angelegt werden Unterscheidung zwischen Referenzen und Zeigern Referenzen müssen immer auf eine vorhandene Variable, Objekt oder Array verweisen Zeiger dürfen irgendwohin zeigen, auch in ungültige Speicherbereiche keine strikt geschachtelten Namensräume flexiblerer Umgang mit Namensräumen undefinierter = globaler Namensraum Trennung zwischen Schnittstelle und Implementierung Schnittstelldateien können flexibel eingesetzt werden für Interfaces gibt es kein spezielles Schlüsselwort Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-6
C++-Dateien und deren Bedeutung *.c Dateien, die mit dem C-Compiler kompiliert werden *.cpp Dateien, die mit dem C++-Compiler kompiliert werden eine cpp-datei enthält den Programmeinstiegspunkt: main() Bsp. Implementierung der Methoden einer Klasse Header-Datei (*.h) enthält oft mehrfach benötigte Definitionen wird nicht direkt kompiliert, sondern in eine oder mehrere cpp-dateien importiert Bsp. Definition der Schnittstelle einer Klasse *.hpp ursprünglich als reine C++-Header-Dateien gedacht selten verwendet, z.b. als Mischung aus h- und cpp-datei Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-7
Programmerzeugung Präprozessor Programmcode darf Makros enthalten Makros werden unmittelbar vor der Kompilation evaluiert Bsp. Substitution von Konstanten, bedingte Kompilation Compiler Syntaxüberprüfung des Quellcodes Erzeugung von Objektdateien (Maschinencode mit unaufgelösten Verknüpfungen zu anderen Objektdateien) Linker (Binder) Erzeugung von Bibliotheken oder ausführbaren Programmen aus einzelnen Objektdateien Verknüpfungen zwischen Objektdateien werden aufgelöst Optimierungen (z.b. Entfernung nicht verwendeter Prozeduren) sind möglich Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-8
Einsprungsfunktion eines Programms Main-Methode ausführbare Programme benötigen einen Einstiegspunkt eine beliebige Objektdatei enthält genau eine main-funktion Standardform int main(int argc, char* argv[]) { // your code return 0; } vereinfachte Form int main() { } // your code int main(int argc, char* argv[]) { } printf("the program arguments are:\n"); for (int i=0; i < argc; i++) printf("%d: %s\n", i, argv[i]); Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-9
One-Pass-Compiler Idee die Kompilation einer cpp-datei verläuft in einem einzigen Ablauf von oben nach unten inkludierte Dateien werden an der Stelle von #include in den Text eingefügt Konsequenzen bevor ein Bezeichner (Variable, Klasse usw.) verwendet werden darf, muss er deklariert bzw. definiert werden Deklaration bzw. Definition eines Bezeichners muss vor seiner Benutzung kompiliert werden zyklische Abhängigkeiten müssen durch Vordeklarationen aufgebrochen werden (Stichwort: Klassen- und Funktionsprototypen) Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-10
Präprozessor #define definiert ein Symbol/Makro mit oder ohne Parameter Präprozessor löst Symbol auf, d.h. ersetzt es durch Ersetzungstext #undef löscht die Definition eines Symbols, d.h. das Symbol ist danach nicht mehr definiert #ifdef und #endif bedingte Kompilation: die Kompilation eines Textblocks ist abhängig von der Definition eines Symbols Beispiel #define WERT 10 #ifdef WERT #define TEXT "Tom" #endif int main(int argc, char* argv[]) { for (int i=0; i < WERT; i++) printf("hello %s\n", TEXT); return 0; } Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-11
Globale Variablen und Methoden Java Main-Methode ist eine Klassenmethode, also Teil einer Klasse Klassen sind Teil eines Packages (evtl. unbenanntes Package) Klassenvariablen gehören zum Namensraum einer Klasse C++ Main-Funktion ist global (Teil des globalen Namensraums) Klassen, Methoden, Variablen sind Teil eines Namensraums (benannt oder global) Globale Variablen und Methoden uneingeschränkte Sichtbarkeit: aus allen Programmteilen können sie verwendet werden (Sichtbarkeit über die Objektdateigrenze hinweg) Verwendung: wenn immer möglich vermeiden, da das Information Hiding Prinzip stark unterwandert wird Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-12
Modulvariablen und Modulmethoden Sichtbarkeitsbereich beschränkt auf die Objektdatei jedoch über Methoden- und Klassengrenzen hinweg Einsatzgebiet bei nicht-objektorientierter Programmierung als Ersatz von Klassenvariablen und -methoden in OO: Einsatz vermeiden #include <cmath> double d = log10(100.0); static int x = 4; double horror() { x *= x; return d*x; } int main(int argc, char* argv[]){ int x = 5; printf("%.2f, %d\n", horror(), x); printf("%.2f, %d\n", horror(), ::x); } Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-13
Einfache Datentypen Infos Speicherbedarf der einfachen Datentypen ist Compiler spezifisch alle ganzzahligen Datentypen (inkl. char) gibt es vorzeichenlos (unsigned) und vorzeichenbehaftet (signed) in der Zweierkomplementdarstellung Typischer Speicherbedarf auf 32-Bit-Plattformen bool 1 Byte // kompatibel mit Integern: false 0 char 1 Byte wchar_t 2 Bytes // wide character z.b. für Unicode short 2 Bytes int 4 Bytes long 4 Bytes // wie long int long long 8 Bytes // wie long long int float 4 Bytes double 8 Bytes long double (10 Bytes) Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-14
Eigene Typenbezeichner Schlüsselwort typedef dient der Festlegung eigener Typenbezeichner Beispiele typedef int INT32; typedef unsigned long long int UINT64; Schlüsselwort using kann in C++11 auch für eigene Typenbezeichner verwendet werden Beispiele (funktionieren in Visual C++ noch nicht) using INT32 = int; using UINT64 = unsigned long long int; Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-15
Automatische Typinferenz (C++11) Schlüsselwort auto bei Variablendefinitionen, wo aus dem Initialisierungswert der Variable der Typ der Variable für den Compiler automatisch ersichtlich ist, kann das Schlüsselwort auto anstatt des konkreten Typs hingeschrieben werden Beispiele auto x = 7; double f(); auto g = f(); Schlüsselwort decltype decltype(x) ist eine Funktion, welche den Deklarationstyp des Ausdruckes x zurückgibt Beispiele decltype(8) y = 8; decltype(g) h = 5.5; Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-16
Konstanten Schlüsselwort const in Java: reserviert, aber nicht benutzt in C++: vielfältiger Einsatz mit unterschiedlicher Semantik hier verwendete Semantik: nach Initialisierung nur noch lesender Zugriff Beispiele const unsigned int SIZE = 1000; const auto LENGTH = 500; const char GRADES[] = { 'A', 'B', 'C', 'D', 'E', 'F' }; const char NOTEN[] = { 1, 2, 3, 4, 5, 6 }; Gleichwertig double const PI = 3.141596; auto const PID2 = PI/2; Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-17
Konstante Ausdrücke Konstanter Ausdruck ein Ausdruck, der zur Kompilations- und Laufzeit den gleichen Wert liefert gute Compiler bestimmen den Wert des konstanten Ausdrucks zur Kompilationszeit und ersetzen den konstanten Ausdruck durch seinen Wert Schlüsselwort constexpr (C++11) Verallgemeinerung des Schlüsselwort const für konstante Ausdrücke, welche auch Funktionsaufrufe und als Spezialfall auch Konstruktoren enthalten dürfen stellt statische Initialisierung zur Kompilationszeit sicher Beispiel constexpr int getfive() { return 2 + 3; } int array[getfive() + 7]; Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-18
Vereinheitlichte Initialisierung (C++11) struct Base { }; struct Derived : public Base { int m_member; Derived(int a1, int a2) : Derived{a1 + a2} {} Derived(int a) : Base{}, m_member{a} {} }; struct Data { int a, b, c; }; Derived obj1{1, 2}; Derived obj2 = {1, 2}; Derived *p2 = new Derived{1, 2}; Data data = {7, 8, 9}; vector<int> vec = {1, 2, 3, 4}; for(auto i : {2, 4, 6, 8}) cout << i << endl; Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-19
Initialisierungslisten (C++11) Initialisierungslisten sind ein neuer C++ Typ Beispiel #include <initializer_list> struct Tuple { int value[]; Tuple(initializer_list<int> v); // #1 Tuple(int a, int b, int c); // #2 Tuple(initializer_list<int> v, size_t cap); // #3 }; Tuple t1{1, 2, 3}; Tuple t2{2, 4, 6, 8}; Tuple t3(4, 5, 6); // Konstruktor #1 wird verwendet // Konstruktor #1 wird verwendet // Konstruktor #2 wird verwendet Randbedingungen wenn die Initialisierungsliste der einzige Parameter ist, kann wie oben gezeigt vorgegangen werden wenn noch weitere Parameter vorhanden sind, dann müssen die geschweiften Klammern verschachtelt werden Tuple t4 = {{1, 2, 3, 4}, 4}; Initialisierungslisten können by-value und by-reference übergeben werden Prof. Dr. C. Stamm Programmieren in C++, FS 13 1-20