750 likes | 917 Views
Object Oriented Programming. Basic techniques Exceptions and exception proof code Templates and generic programming. Car id Accelerate (). Class vs. object. A class is a programming language construct that is used to group related instance variables and methods
E N D
Object Oriented Programming Basic techniques Exceptions and exception proof code Templates and generic programming
Car id Accelerate() 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 class Car { int id; ..... public: void Accelerate(); }; Car myauto, otherauto; myauto : Car otherauto : Car
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 class Car { int id;public: Car (int newId); void Accelerate(); operator ==(Car &); }; Car myauto(3); myauto.Accelerate(); if (myauto==otherauto) ....; Methods • plain • constructors • operators Attributes Properties (java, c#, managed c++)
Constructor class Car { int id;public: Car (int newId); Car (Car model); void Accelerate(); }; Car myauto(3); Car mycopy(myauto); myauto.Accelerate(); • Constructor is called when object is created • There can be many versions of constructors • The default (non-parameters) constructors should be defined only if necessary to avoid improperly initialised objects
Destructor class Car { int dbconnection;public: Car (int newId); ~Car () { Close(dbconnection); } }; {Car myauto(3); .... } • 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 • InJava,C# - only in extraordinary cases – when managed code deals with unmanaged resources
Truck capacity Unload() Derivation Car Accelerate() Decelerate() 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();
Aggregation Car motor:Engine Accelerate() Decelerate() Class may contain many fields. fields may be objects of other classes class Engine { public: void Start(); void Stop(); }; class Car { Engine motor; public: void Accelerate(); void Decelerate(); }; Engine Start() Stop()
Derivation vs. aggregation Car motor:Engine Accelerate() Decelerate() Engine Start() Stop() • Sub class (i.e. derived class) is a special case of superclass. Egg.: 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. 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();
Truck capacity Unload() Derivation again Container Capacity Load() Unload() • C++: Multiple class derivation • C#, Java: Multiple interface derivation Car Accelerate() Decelerate()
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 Car motor:Engine Accelerate() Decelerate() Boat motor:Engine SailFaster() SailSlower() Engine Start() Stop() Engine Start() Stop() Amphibious
Single vs multiple derivation C#, Java: derivation from (implementation of) multiple interfaces is allowed ICar Accelerate() Decelerate() IBoat SailFaster() 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 polymorphism Car Accelerate() C++ virtual is necessary in base class, in derived identical functions will be automatically treat as virtual (but IT IS RECOMMENDED to write virtual specificator again C#: virtual in base and overriden in derived is required Java: every overriding is virtual Truck Accelerate() Uscases: using pointer or reference and call (C#, and JavaNote in C#, Java we have always references using anothing (ie. object in c++ as well) and call to function that calls another, virtual function
Subtype polymorphism – case 1 Car Accelerate() class Car { public: virtual void Accelerate(); // 1st }; class Truck { public: virtual void Accelerate(); // 2nd }; Car mycar; mycar.Accelerate(); // ??? Truck mytruck; mytruck.Accelerate(); // ??? Truck * mytruckPtr = new Truck; mytruckPtr->Accelerate(); //??? Car * mycarPtr = new Car; mycarPtr->Accelerate(); //??? delete mycar; mycarPtr = new Truck; mycar->Accelerate(); //??? Truck Accelerate()
Subtype polymorphism – case 2 Car Accelerate()Test() class Car { public: virtual void Accelerate(); // 1st virtual void Test() { Accelerate(); } }; class Truck { public: virtual void Accelerate(); // 2nd }; Car mycar; mycar.Test(); // ??? Truck mytruck; mytruck.Test(); // ??? Please note that in fact: .... virtual void Test() { this->Accelerate(); } Truck 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 • 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 superclass 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 Order of operations: • allocation of Picture (1) • constructor of Picture (2) • allocation of sound (3) • constructor of sound (4) Document() { m_picture = new Picture(); m_sound = new Sound(); } ... Document doc; 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 1During construction of sound the exception was raised ( but what if the destructor of picture raises the second exception) 2During 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 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: • normal functions (specialised template functions) if ideal matching is possible • templates and possible template instances
Template - matching • When type of template is determined there are considered: • specialised function • templates and possible template instances • Only ideal fit of parameters is possible - considermax(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);