Object Oriented Programming Basic techniques Exceptions and exception proof code Templates and generic programming Class vs. object A class is a programming language construct that is used to group related instance variables and methods Object is an instance of a class Class is a type of object Car class Car { id int id; Accelerate() ..... public: void Accelerate(); myauto : Car }; otherauto : Car Car myauto, otherauto; Classes vs. structures C++: Classes are very similar to structures Access - class content is private by default Class can contain virtual methods C#: Classes are reference types, structure are value types Java: No structures exists Encapsulation, hermetization A class content may be accessible for class exterior or not Possible accessors: public, private, protected, internal (C#) Fields should be not accessible from outside of class class Car { int id; public: void Accelerate(); }; Car myauto; myauto.Accelerate(); //myauto.id = 3; Class content Methods plain constructors operators Attributes class Car { int id; public: Car (int newId); void Accelerate(); operator ==(Car &); }; Car myauto(3); myauto.Accelerate(); if (myauto==otherauto) ....; Properties (java, c#, managed c++) Constructor Constructor is called when object is created There can be many versions of constructors The default (nonparameters) constructors should be defined only if necessary to avoid improperly initialised objects class Car { int id; public: Car (int newId); Car (Car model); void Accelerate(); }; Car myauto(3); Car mycopy(myauto); myauto.Accelerate(); Destructor Destructor is called when object is destroyed There can be only one destructor The destructor should be defined only if some clean-up is necessary In Java, C# - only in extraordinary cases – when managed code deals with unmanaged resources class Car { int dbconnection; public: Car (int newId); ~Car () { } Close(dbconnection); }; { } Car myauto(3); .... Derivation Super class (i.e. base class) means less specialized class, class with less components Sub class (i.e. derived class) means specialised class or the special case of class class Truck : public Car { int capacity; public: void Unload(); }; Truck v; v.Accelerate(); Car Accelerate() Decelerate() Truck capacity Unload() Aggregation Car Class may contain many fields. fields may be objects of other classes motor:Engine class Engine { public: void Start(); void Stop(); }; class Car { Engine motor; public: void Accelerate(); void Decelerate(); }; Decelerate() Engine Start() Stop() Accelerate() Derivation vs. aggregation Sub class (i.e. derived Engine class) is a special case Start() of super class. Egg.: Stop() Truck is a special case of Car External class uses some functions from internal class but is not similar to it. Egg.:Car is not a special case of Engine. Car motor:Engine Accelerate() Decelerate() Truck capacity Unload() Derrivation introduces closer relation than agregation so if not sure - better prefere aggregation Object vs. class again attributes, methods related to object static – means attributes, methods related to class i.e. common for all the object of this class class Car { Engine motor; static int cnt=0; public: static GetCount() { return cnt; } void Accelerate(); void Decelerate(); }; C++: Car::GetCount() or mycar.GetCount(); C#: Car.GetCount() Java: Car.GetCount() or mycar.GetCount(); Derivation again Container Capacity Car Load() Accelerate() Unload() Decelerate() C++: Multiple class derivation C#, Java: Multiple interface derivation Truck capacity Unload() Basic techniques Concepts of interface Interface – defines a set of functions/properties that should be delivered (implemented) by a class (Java, C#, managed c++) Abstract class – class that implements not all of the expected functions //C# code interface IVehicle { public: void Accelerate(); void Decelerate(); }; class Car : IVehicle { .... }; IVehicle v = new Car; v.Accelerate(); Single vs multiple derivation C++: derivation from multiple class is allowed Engine Start() Stop() Car Boat motor:Engine Engine motor:Engine Accelerate() Start() SailFaster() Decelerate() Stop() SailSlower() Amphibious Single vs multiple derivation C#, Java: derivation from (implementation of) multiple interfaces is allowed ICar IBoat Accelerate() SailFaster() Decelerate() SailSlower() Amphibious Derivation forbidden? Why? - to not modify the class by client, - to not extend, change etc. C#: sealed Java: final Overloading ... multiple functions with same name but different sets of arguments class Car { public: void Accelerate(int x); void Accelerate(double x); void Accelerate(Car &c); }; Overriding ... redefinition of function in sub class class Car { public: void Accelerate(); // 1st }; class Truck { public: void Accelerate(); // 2nd }; Car mycar; mycar.Accelerate(); // 1st or 2nd ??? Truck mytruck; mytruck.Accelerate(); // 1st or 2nd ??? Polymorphism def. Allowing a single definition to be used with different types of data Types of polymorphism. : subtype polymorphism parametric polymorphism = generic programming (i.e. templates, generic types) Subtype polymorphismCar C++ virtual is necessary in base class, in derived identical functions will be Accelerate() automatically treat as virtual (but IT IS RECOMMENDED to write virtual specificator again C#: virtual in base and overriden in derived Truck is required Java: every overriding is virtual Accelerate() Uscases: 1) using pointer or reference and call (C#, and Java Note in C#, Java we have always references 2) using anothing (ie. object in c++ as well) and call to function that calls another, virtual function Subtype polymorphism – case 1 class Car { public: virtual void Accelerate(); // 1st Car Accelerate() }; class Truck { public: virtual void Accelerate(); // 2nd }; Truck Car mycar; mycar.Accelerate(); // ??? Accelerate() Truck mytruck; mytruck.Accelerate(); // ??? Truck * mytruckPtr = new Truck; mytruckPtr->Accelerate(); //??? Car * mycarPtr = new Car; mycarPtr->Accelerate(); //??? delete mycar; mycarPtr = new Truck; mycar->Accelerate(); //??? Subtype polymorphism – case 2 class Car { public: virtual void Accelerate(); // 1st virtual void Test() { Accelerate(); } Car Accelerate() Test() }; class Truck { public: virtual void Accelerate(); // 2nd Truck }; Accelerate() Car mycar; mycar.Test(); // ??? Truck mytruck; mytruck.Test(); // ??? Please note that in fact: .... virtual void Test() { this->Accelerate(); } Parametric polymorphism class Car {}; class Plane {}; class Dispatcher { LoadTo(Car & c); LoadTo(Plane & p); } Car c; Plane p; Dispatcher d; d.LoadTo(p); d.LoadTo(c); This mechanism is extended in templates Namespaces Limiting of scope of identifiers to avoid conflicts between different modules etc. namespace A { float x; }; namespace B { int y; int x; namespace A { float z=x; using A::z; z = B::y; using namespace A; using namespace B; x=y; // ?? }; }; Exception and exception proof code Exception Throwing of exception causes making a copy of exception object cleaning of stack: execution of destructors of local objects removing of local objects return of execution control to the range above Throwing of exception Throwing of exception C#, Java: throw new Exception; C++: throw Exception; throw „abc”; Please note that the object created by „new” should be destroyed by programmer. So however the construction „throw new...” is syntactically corrected it is used hardly ever consider catch(...) Catching of exception try { .... } catch(Exception1 e) {...} catch(Exception2 e) {...} catch(Exception e) {...} There is executed the first and only the first matched clause catch, if any fits the current scope will be leaved If Exception2 is super class of Exception1 the clause for Exception2 should be placed after clause for Exception1 Releasing of resources What kind of resources we should take care about: memory (for C++) system objects GDI objects db connections etc. other not managed resources The objects pointed above should be released by programmer Cleaning code in managed languages The finishing code should be repeated for a normal finish of try code and every catch clause. To avoid of multiplication of code there is available in C#, Java and managed C++ the finally clause. try { .... } finally { releasing_of_resources ; } catch(Exception1 e) {...} catch(Exception2 e) {...} catch(Exception e) {...} Releasing of resources What kind of resources we should take care about: memory (for C++) system objects GDI objects db connections etc. other not managed resources The objects pointed above should be released by programmer Releasing resources in C++ try { // there may be the inner try blocks .... // releasing of resources } catch(...) { // releasing of resources throw; } Issues: ● ● releasing code has to be written in two places what about return instruction? Destructor should be called in automate way class wrapper { public: Resource m_resource; wrapper(Resource &resource); ~wrapper() { //releasing of resource } }; { wrapper w (new car); working_with (w.m_resource); // throw Exception; working_with (w.m_resource); } Wrappers – some issues Unnatural way of usage resource: overriding of operators *,-> Handling of wrapper copying reference counting (reference semantics) resource copying (value semantics) forbidding of copying Dedicated wrapper for particular resource type: template using What about unfinished objects class Picture { }; class Sound {}; class Document { Picture *m_picture; Sound *m_sound; Document() { m_picture = new Picture(); // can be raised exception ? m_sound = new Sound(); // can be raised exception ? } ~Document(); // delete m_picture, m_sound }; Document doc; Constructor – more problems Document() { m_picture = new Picture(); m_sound = new Sound(); } ... Document doc; Order of operations: allocation of Picture (1) constructor of Picture (2) allocation of sound (3) constructor of sound (4) What about exception in 1,2,3,4 Destructor is called only for properly created and constructed objects so destructor of Document wont be called in case of exception in constructor. Constructor – more problems Document() : m_picture (NULL), m_sound(NULL){ try { m_picture = new Picture(); m_sound = new Sound(); } catch(...) { delete m_picture; // legal for m_picture==NULL delete m_sound; } } Problem: The cleaning code has to be placed in destructor as well Safe solution class Picture { }; class Sound {}; class Document { wrapper<Picture> m_picture; wrapper<Sound> m_sound; Document() : m_picture (new Picture()) , m_sound(new Sound()) { } ~ Document() { }; }; .... Document doc; What about destructor ? Document() : m_picture (new Picture()) , m_sound(new Sound()) 1 {} ~ Document() { }; 2 1 During construction of sound the exception was raised ( but what if the destructor of picture raises the second exception) 2 During removing of Document object (because of exception somewhere in the code) the destructor of Picture raises the new exception ) Destructor cannot... • raising of a new exception when a previous one is still not handled properly is forbidden so • DESTRUCTOR is not expected to throw a new exception in any circumstances!!! Templates Templates motivation Many same functions (i.e. same names) with different types – means overriding Many same functions (i.e. same names) with different types, but identical logic int max(int a, int b) { return a>b ? a : b; } long max(long, long) .... float max(float, float) .... double max(double, double) .... C++: using macros #define max(a,b) ((a)>(b) ? (a) : (b) ) x = max(3,5); Drawbacks: hard debugging surprises..., egg.: max(x++, y) Function template C++ Definition: template <class T> T max(T a, T b) { return a > b ? a : b; } Usage: max(3, 5); max(2.5, 5.5); max(2, 1.5); // int czy float ? Specialisation: char* max(char*a, char*b) {return strcmp(a,b)>0 ? a : b; } max("xxx","yyy"); Please note that compiler requires the body of template when used so usually templates are defined in .h file Function template - properties Global Parameter(s) might be types Not every parameters of template function have to be depend on template parameter template <class T> T gen(T, int cnt) { .... } ; Type of template instance is recognised basing on parameters long m = max(1, 2) int m = max(1, 2) When a function to call is determined there are considered: 1. 2. normal functions (specialised template functions) if ideal matching is possible templates and possible template instances Template - matching 1. 2. When type of template is determined there are considered: specialised function templates and possible template instances Only ideal fit of parameters is possible - consider max(1, 2.5) New compilers allows trivial conversions D* to B*, D& to B&, T to const & T, T& to const T &, T* to const T* When function address is taken the type of desired pointer (to function) is considered int (fun*)(int, int); Template - parameters Int x,y; xxx(x,y); template <class T> T xxx(T, T&) { .... } ; template <class T, class Z> T xxx(T, Z&) { .... } ; yyy(x,&y); template <class T, class Z> T xxx(T, Z*) { .... } ; template <class T, class Z> T xxx(T, Z) { .... } ; F. template – returned type Templates have to differ not only with returned type (why?) template <class T> T * gen(int a) { return new T[a]; } int * ti = gen(3); double * td = gen(3); Solution: additional parameter template <class T> T * gen(T, int a) { return new T[a]; } int * = gen(2, 100); Class template template <class T> class vector { T * m_array; public: vector () { m_array = new T[DEFSIZE]; } vector (long size) { m_array = new T[size]; } ~vector () { delete m_array; } void put(T element, long pos); {m_array[pos] = element; } T get(long pos) { return m_array [pos]; } T& operator[](long pos) { return m_array[pos]; } }; vector<int> vi, vii(100); typedef vector<int> VECTORINT; VECTORINT vi1, vii1(100); Template instance vs class instance template <class TINDX, class TELEM> class vector { TELEM * m_array; public: vector (TINDX size); }; Template instance (means class): vector<long, int> class instance (means object) : vi(100); Template & methods template <class T> class vector { T * m_array; public: vector (long size); T& operator[](long pos) { return m_array[pos]; } }; template <class T> T& vector<T>:: operator[](long pos) { return m_array[pos]; } template <class T> vector<T>::vector(long size) : m_array(new T[size]) {} Functions might be defined in class body or not Specialisation in class templates Specialised class class vector <char> { ....... }; specialised method long & vector <long>::operator[](long pos) { .... } Specialised attribute vector<long>::refcount = -1; Static, enum template <class T> class vector { T * m_array; static long refcount = 0; // new compilers only.... enum ETyp { t1, t2, t3 }; }; // older compilers require // explicite declaration template <class T> long vector<T>::refcount = 0; vector<long>::ETyp vaiable; Static attribute is „common” for particular template instance Functions and classes template <class T> class vector { T * m_array; public: vector (long size); T& operator[](long pos) { return m_array[pos]; } }; template <class T> Creator <class T> vector<T> fun (T, int cnt) { return vector<t>(cnt); } Instead of global function template it is worth to consider static function in vector class template... Aggregation? template <class T> class vector { T * m_array; public: vector (long size); T& operator[](long pos) { return m_array[pos]; } }; template <class T> class tester { T m_element; vector<T> m_vector; ... } template <class T, class Z> class tester { T m_element; vector<Z> m_vector; ... } Inner class? template <class T> class vector { public: class helper { ... }; private: T * m_array; public: vector (long size); }; vector<int> v(5); vector<int>::helper h; Only the new C++ compilers Template methods of class? class Container { ... public: template <class T> void assign(T element) { ... }; ... }; template <class ELEM> class Container { ... void assign (const ELEM element) { ... } public: template <class T> void assign(T element) { ... } }; Only the new C++ compilers Template in template? template <class ELEM> class vector { public: template <class T> class adaptor { ... }; private: ELEM * m_array; public: vector (long size); }; vector<int> v(5); vector<int>::adaptor<MyClass> h; Only the new compilers Class template parameters template <class TINDX, class TELEM> class vector { TELEM * m_array; public: vector (TINDX size); }; vector<long, int> vi(100); Class template parameters ... template <long size, class TELEM> class vector { TELEM * m_array; public: vector () { m_array = new T[size]; } ... }; vector<100, int> vi; thank to using the number code can be determined in compilation time Default parameters template <class TELEM, class INDEX=long> class vector { TELEM * m_array; public: vector () { m_array = new T[size]; } TELEM get(INDEX i ) { .... } ... }; vector<int> vi; vector<int,short> vismall; Templates vs. deriving Class Instance of template (== class) Template Class can derive from class, instance of template Instance of template can derive from class, instance of template class neither instance of template can not derive from template Template can derive from class, instance of template or template Use cases Class from class - Nothing new :-) Class from instance of template – modified template behaviour class VA : public vector <char> { ... }; Instance of template from class/ Instance of template specialisation of template on the class level class vector <char> : public vectorChar : { ... }; class vector <char> : public array<char> : { ... }; Use cases part 2 Deriving template from class/instance Reduction of code overhead Hiding the code against template end user (programmes have access to template source code but a base class is delivered as binaries) template <class T> class vector <T> : public vectorBase { ... }; Deriving template from template Extension of template logic template <class T> class vector <T> : public container<T> { ... }; Explicit zero initialization Problem: uniformed code for zeroing user types and built-in types int x = int(); A a = A(); template <class T> void fun(T t) { T local = T(); }; C++: Template instances When a template is used for any type the compiler creates the separate code for this template instance E.g. the following cases vector<int> vector<double> vector<car> imply generation (during compilation) 3 different classes (with all the member functions) C# - generic types Availiable since Framework 2.0 (VS2005) public class Cont<T> { private T field; public void Store(T arg) { field = arg; } } Cont<int> c = new Cont<int>(); c.Store(10); Cont<string> cs = new Cont<string>(); cs.Store(„abc”); C#: Generics public class Cont<T> : where T : IToDo{ private T field; public void Store(T arg) { field = arg; field.DoSomething(); } } public interface IToDo { void DoSomething(); } Cont <MyClass> c = new Cont <MyClass>(); c.Store(new MyClass("ABC")); For unbounded types it is only possible to convert to System.Object and to compare to null value C#: Constraints on T parameter where T: struct - argument must be a value type where T : class - argument must be a reference type, including any class, interface, delegate, or array type where T : new() - the type argument must have a public parameterless constructor where T : <base class name> - the type argument must be or derive from the specified base class. where T : <interface name> - the type argument must be or implement the specified interface. Multiple interface constraints can be specified. The constraining interface can also be generic. where T : U - the type argument supplied for T must be or derive from the argument supplied for U. This is called a naked type constraint. C#: Generic interfaces public Interface IPrinter <T> { void Print(T t); } class IntPrinter : IPrinter < int> { public void Print (int w) { ... } } class GenericPrinter <T> :IPrinter<T> { public void Print (T w) { ... } } C#: Generic methods static void Swap<T>(ref T lhs, ref T rhs) { T temp; temp = lhs; lhs = rhs; rhs = temp; } public static void TestSwap() { int a = 1; int b = 2; Swap<int>(ref a, ref b); Swap(ref a, ref b); System.Console.WriteLine(a + " " + b); } C#: Generic methods In comparing to C++ the separate instances for all the value types are generated a common instance for all the reference types is used Java: generic types public interface Iterator<E> { E next(); boolean hasNext(); } public interface List<E> { void add(E x); Iterator<E> iterator(); } List<Integer> myIntList = new LinkedList<Integer>(); myIntList.add(new Integer(0)); Integer x = myIntList.iterator().next(); Java: wildcards void printCollection(Collection<?> c) { for (Object e : c) { System.out.println(e); } } Java: wildcards with bounding public abstract class Shape { public abstract void draw(Canvas c); } public class Circle extends Shape { ... } public class Rectangle extends Shape {... } // shapes only -> List<Shape> public void drawAll(List<Shape> shapes) { for (Shape s: shapes) { s.draw(this); } } // shapes and derrived List<Rectangle> public void drawAll(List<? extends Shape> shapes) { ... }