Documentation http://www.math.upb.de/~robsy/lehre/programmierkurs2008/ Programming / Documentation Slide 42
Memory Management (I) There are several types of memory which a program can access: Stack Every program has its own last-in-first-out (LIFO) memory for automatically constructed (local) variables. Allocation is fast, but memory is limited ( Stack overflow ). Free Store/Heap The RAM. The place where dynamically allocated memory, i.e. allocated with malloc or new, is taken from. Allocation is expensive (in terms of computer power) but the amount of memory is only limited by the operating system or the hardware. Large objects must be created on the heap. String literals and constant data occupy neither of the above. Programming / Memory Management Slide 43
Recap: Pointers Memory is represented as a linear line of bytes, each accessible through it's memory address. Pointers to a variable contain the memory address of the variable. They represent one level of indirection. Requesting the value to which a pointer refers is called dereferencing the pointer. The operating system shields programs from each other so they cannot interfere with each other by accessing the other programs memory ( Segmentation violation ). The null pointer cannot be dereferenced. Doing this will crash your program. Just as a an integer is different from a double, a pointer to an integer is different from a pointer to a double. Programming / Memory Management Slide 44
Recap: Pointers (II) There are several operators in C++ for handling pointers: The dereference operator * int* p // pointer to an integer *p // value of the pointed to integer The address-of operator & int a = 10; int* p = &a; // p points to a *p = 70; // value of the pointed to integer is changed Call function of a class through a pointer to the class -> class Example; // class with a function print() Example* p =...; // p should point to an instance (*p).print(); // dereference p, than call print() p >print(); // the same Programming / Memory Management Slide 45
Recap: Pointers (III) int a = 1, b = 20; // variables on the stack int* y = 0; // a null pointer to an integer. the pointer // itself is also on the stack, the referenced // object could be anywhere (or nowhere) int c = *y; // ERROR int *z = &a; // z points to a, y = &b; // y points to b *z = *y; // assign the value of where y points to // wherever z points. => a == 20 // void is not a type of real data, but void* is the general // type of a pointer. A pointer (the address it points to) // can be printed by casting it to a void pointer cout << (void*)z << endl; // e.g. 0xBAF44200 cout << *z << endl; // 20 Programming / Memory Management Slide 46
Memory Management (II) In C++, objects on the heap are created using 'new': class Example; Example d* = new Example(); // allocate memory, // then run constructor delete b; // call destructor, // then release the occupied memory The new operator always returns a pointer to the object created. If this pointer is lost, the object is lost and the memory cannot be reclaimed. Delete needs the pointer to the object that is to be destroyed. The computer keeps track of the occupied memory and releases it. Programming / Memory Management Slide 47
The this Pointer Inside a method of a given class, there is always a pointer that points to the current object: class Example { void f1() { g(); } // this >g(); void g() { } void f2() const { this >g(); } // ERROR: this is of // type const Example* void print() { cout << (void*)this << endl; } Example* address() { return this; } }; Example a; // this == &a Example* b = new Example(); // this == b You cannot change the value of the 'this' pointer. Normally, you don't need to explicitly write 'this->' everywhere, the pointer is included implicitly. Programming / Memory Management Slide 48
OOP in C++ (I) A Base class: class Base { public: Base(int i) : v(i) { } virtual ~Base() { } }; virtual void x() = 0; // pure virtual function virtual void y(int i) { } // virtual function with // default implementation protected: int v; A Base class must declare all polymorphic functions virtual, the derived class then declares exactly the same function. If a class is to be used as a base class, it should declare the destructor virtual, so the correct one is called at runtime when using delete. Programming / Object Oriented Programming Slide 49
OOP in C++ (II) The derived class class Derived : public Base { public: Derived(int i) : Base(i) { } // call Base constructor ~Derived() { } // Base destructor is called // automatically void x() { /* do something */ } void y(int i) { /* do something else */ } }; Base The constructors of a derived class should first call the corresponding constructors of the base class with proper arguments, then initialize member variables. Derived With public inheritance, all methods and data structures of the base class are accessible in the derived class if not declared private. Programming / Object Oriented Programming Slide 50
OOP in C++ (III) Example: void my_function() { Derived d* = new Derived(1); // an instance of Derived Base* b = d; // disguised as a Base object d >x(); d >y(1); // calls Derived::x() and Derived::y(int) b >x(); b >y(2); // so do these delete b; } The constructor of the Base class is executed first, then the destructor of the Derived class. Destructors are executed in the opposite order. Without the virtual destructor in class Base, the delete statement would not call the destructor in Derived, but the Base destructor. This would entail all kinds of negative effects ( memory leaks, crashes, ). Programming / Object Oriented Programming Slide 51
Stream Objects (I) cout and cerr are instances of a class named basic_ostream, cin of basic_istream. They write to and read from the console single characters. Subclasses of basic_{i,o}stream are basic_{i,o}fstream which are objects that implement writing to and reading from files. #include <fstream> std::ofstream* Ausgabe = new std::ofstream(); Ausgabe >open( dateiname, std::ios::out std::ios::trunc); if( Ausgabe >rdstate() == std::ios::failbit ) { // Error opening file } // write stuff to file (*Ausgabe) << Hello File << std::endl; Ausgabe >flush(); Ausgabe >close(); delete Ausgabe; Programming / Object Oriented Programming Slide 52
Stream Objects (II) The same file can then be opened for reading and the string can be read back: #include <fstream> std::ifstream* Eingabe = new std::ifstream(); Eingabe >open( dateiname, std::ios::in); if( Eingabe >rdstate() == std::ios::failbit ) { // Error opening file } // read stuff from file std::string text; (*Eingabe) >> text; Eingabe >close(); delete Eingabe; Programming / Object Oriented Programming Slide 53
Stream Objects (III) Stream Objects are at first a little bit more difficult to use than the C function printf(), scanf(), etc. But they have advantages: Compatibility: stream objects are meant to generate ASCII output and not binary files. The files can be copied and read back on other computer with different architectures. Type safety: The stream does the conversion while reading and writing. If, for example, you want to read a number, but the stream contains letters, an error is raised. Extensibility: By defining stream operators for classes, objects can be saved to disk and loaded back. Of course they are a little slower than reading raw binary data in C, but this can be neglected most of the time. Programming / Object Oriented Programming Slide 54
For example: Write to ostream Stream Objects (IV) #include <iostream> class Complex { public: friend ostream& operator<<( ostream&, const Complex& ); // as before private: double real, img; }; ostream& operator<<( ostream& o, const Complex& c ) { o << c.real << << c.img; return o; } ostream functions for classes must have this signature. They are usually declared friend to access private data members in the class. Programming / Object Oriented Programming Slide 55
Stream Objects (V) Reading Back: #include <iostream> class Complex { public: friend istream& operator>>( istream&, Complex& ); // as before private: double real, img; }; istream& operator>>( istream& i, Complex& c ) { i >> c.real >> c.img; return i; } istream functions for classes must change the object, so it cannot be given as const. Programming / Object Oriented Programming Slide 56
Stream Objects (VI) Since {i,o}fstreams are also {i,o}streams, these operators can also be used to save to and load from files: ofstream Ausgabe( test, std::ios::out std::ios::trunc ); Complex c(1,2); Ausgabe << Test: << c; Ausgabe.close(); Complex d(0,0); ifstream Eingabe( test, std::ios::in ); std::string text; Eingabe >> text >> d; Eingabe.close(); cout << Gelesen : << d; Programming / Object Oriented Programming Slide 57
Design Patterns A Design Pattern is a general technique used to solve a class of (related) problems Design Patterns serve a specific purpose Knowing of them is like knowing a trick in a mathematical proof Holub on Patterns Design Patterns: Elements of Reusable Object-Oriented Software Programming / Design Patterns Slide 58
Design Patterns Examples Creational Patterns: Abstract Factory (create an object knowing only the interface) Singleton (constrain the number of instances of a class) Structural Patterns: Adapter (make a class appear to support another interface) Decorator (attach/remove features of an object at runtime) Facade (provide a single interface for a complete subsystem) Behavioral Patterns: Iterator (access elements sequentially) Command (encapsulate a unit of work into an object) Visitor (add features to a set of elements) Programming / Design Patterns Slide 59
Purpose: Iterator (Generalized Pointer) access the elements of an aggregate object sequentially without exposing how the aggregation is implemented Promotes reuse by hiding implementation A client may modify the elements potentially damaging the aggregate (e.g. change the key in a sorted map) Iterators often become undefined when elements are stored in the container and new memory must be allocated iterator it = container.begin(); double v = *it;// dereference operator ++it; // traverse to next element it; // traverse to previous element it += 3; // random access iterator: traverse 3 elements it2 = it + 5; int distance = it2 it; // it2 == it + distance => 5 Programming / Design Patterns Slide 60