Programowanie obiektowe
Transkrypt
Programowanie obiektowe
Programowanie obiektowe dr inż. Marcin Pietroo History of programming languages Języki programowania TIOBE LIST: 1. C 2. C++ 3. Objective-C 4. Java 5. C# 6. Visual Basic 7. PHP 8. Python 9. JavaScript 10.Visual Basic .NET 11. Ruby 12. Transact-SQL 13. Perl 14. F# 15. Język asemblera 16. Lisp 17. PL/SQL 18. MATLAB 19. Delphi 20. Object Pascal Programming languages Programming languages • set of syntax rules • semantic Choosing language for implementation: • efficiency • available libraries • experience • domain of implementation Programming languages • Newer languages with higher abstraction • old languages were low level languages strictly based on CPU architecture • portability and abstraction shorten time of software development, error risk (very often worse efficiency) Elements of programming lanaguages • • • • syntax semantic data types standard libraries Programming languages – syntax and semantic • Lexems (token) definitions • Syntax rules Syntax defined by regular expressions and BNF notation Gramar definition BNF notation is a production rules set: • <symbol> ::= <expression with symbols> Semantic of used symbols is as follows: • < – left boundary of symbol • > – right boundary of symbol • ::= – is defined as • | – or Above symbols are meta language symbols. BNF – liczba naturalna • <zero>::= 0 • <non zero numbers>::= 1 | 2 | 3 | 4 | 5 | 6 | 7 |8|9 • <digit>::= <zero> | <non zero number> • <digits> ::= <digit> | <digit><digits> • <positive integer number>::= <digit> | <non zero digit><digits> BNF – C language conditional_expression : logical_or_expression ('?'^ expression ':' conditional_expression)? ; logical_or_expression : a=logical_and_expression ('||'^ b=logical_and_expression)*; logical_and_expression : inclusive_or_expression ('&&'^ inclusive_or_expression)* ; inclusive_or_expression : exclusive_or_expression ('|'^ exclusive_or_expression)* ; BNF – C language compound_statement : '{' declaration* statement_list? '}'; statement_list : statement+ -> ^(STMT statement+); FLOATING_POINT_LITERAL : ('0'..'9')+ '.' ('0'..'9')* Exponent? FloatTypeSuffix? | '.' ('0'..'9')+ Exponent? FloatTypeSuffix? | ('0'..'9')+ Exponent FloatTypeSuffix? | ('0'..'9')+ Exponent? FloatTypeSuffix ; Programming languages – data types • integers • floating points (float, double) • text data (char) Standard libraries • • • • • input/output functions files system handling multithreading operating memory handling basic data types and procedures to processing them • text data structures Types of errors • • • • • • lexical error syntax error casting error semantic error execution error logic error Errors • • • • foor (int i = 0; i < 100; i++) - lexical x+1 = x - syntax for (int i = 0, i < 100, i++) - syntax main() {i = 0;} - semantic Programming languages processing • compilation – source code is translated to machine code. Compiled programming languages • interpretation – source code is translated online and executed by special program called interpreter. Interpretated programming languages Classification of programming languages • programming paradigms (imperative, functional, declarative) • type of generating machine code • control of data types compatibility (e.g. dynamic typed) • type of execution (compiled, interpretated) • level of abstraction (low or high level) • purpose (database modification, markup languages, bash languages, hardware languages etc.) Compilation - lexer • The process of converting a sequence of characters (such as a computer program or web page) into a sequence of tokens • A program that performs lexical analysis may called lexer, tokenizer, or scanner ("scanner" is also used to refer to the first stage of a lexer). Compilation - lexer • lexer is generally combined with a parser, which together analyze the syntax of programming languages, web pages. • Regular expressions (identify tokens) • finite automata (finite state machine) with state table Lexer • sum = i + 8; Lexem Token category sum "Identifier" = "Assignment" i „identifier" + "Addition" 8 "Integer literal" ; "End of statement" Compilation - parser • Parsing or syntactic analysis is the process of analysing a string of symbols, either in natural language or in computer languages, conforming to the rules of a formal grammar. • Parser get lexer output as an input • Generate Abstract Syntax Tree (AST) Parser • Top-down parsing - top-down parsing can be viewed as an attempt to find left-most derivations of an inputstream by searching for parse trees using a top-down expansion of the given formal grammar rules. Tokens are consumed from left to right. • Bottom-up parsing - a parser can start with the input and attempt to rewrite it to the start symbol. Intuitively, the parser attempts to locate the most basic elements, then the elements containing these, and so on. LR parsers are examples of bottom-up parsers. Another term used for this type of parser is ShiftReduce parsing. Proces kompilacji • lexer –> tokens –> syntactic analysis –> • parse tree (AST, intermadiate representation) –> compiler, interpreter, translator -> • other language, virtual machine -> • machine code etc. Abstract Syntax Tree FUNC_DEF FUNC_BODY DECL DECL COMPOUND_STMT EXPR Time_START Time_END COMPOUND_STMT EXPR EXPR EXPR EXPR i = 6 EXPR EXPR Compilation – tools for lexer and parser generating • • • • • Yacc ANTLR SUIF Flex Ragel C language • • • • variables basic data types (int, float, double, char etc.) arrays (static and dynamic) structures C language • pointers (int*, double* etc.) • references (int & etc.) C language • functions (parameters by value and addresses, local variables, list of parameters etc.) • conditional instructions (if etc.) • loops (for, while etc.) C language Memory allocation: - malloc, realloc … - free Struktury danych • • • • • preprocesor define (literal values, macros) include ifdef … Data structures • • • • • List Vektor Hashmap Stack Set Data structures • Binary trees • Red black trees • Heap List implementation • How list can be implemented in C? List struct element { int value; struct element *next; }; struct element* head = malloc(sizeof(struct element)); head->value = 1; head->next = NULL; Lista struct element* addLastElement(struct element* tail, int val) { struct element* new_tail = malloc(sizeof(struct element)); new_tail->value = val; new_tail->next = NULL; tail->next = new_tail; return new_tail; } struct element* addFirstElement(struct element* head, int val) { struct element* new_head = malloc(sizeof(struct element)); new_head->value = val; new_head->next = head; return new_head; } Lista struct element* removeFirstElement(struct element* head) { struct element* new_head = head->next; free(head); return new_head; } void print_list(struct element * head) { struct element * current = head; while (current != NULL) { printf("%d\n", current->value); current = current->next; } } Lista struct element* removeElement(struct element* head, int nr) { struct element * current = head; struct element * previous = head; int count = 0; while (current != NULL) { count++; if (count == nr) { current = current->next; previous->next = current; } previous = current; } } Task • Bidirectional list Data structures • Graph Task – tree implementation Data structures • Tree traverse • Methods of tree traverse? Tree traverse PRE-ORDER(node_v) { print node_v.value jeżeli node_v.left_child != null to PRE-ORDER(node_v.left_child) jeżeli node_v.right_child != null to PRE-ORDER(node_v.right_child) } IN-ORDER(node_v) { jeżeli node_v.left_child != null to IN-ORDER(node_v.left_child) wypisz node_v.value jeżeli node_v.right_child != null to IN-ORDER(node_v.right_child) } POST-ORDER(node_v) { jeżeli node_v.left_child != null to POST-ORDER(node_v.left_child) jeżeli node_v.right_child != null to POST-ORDER(node_v.right_child) wypisz node_v.value } Basic algorithms - Sorting - Text algorithms - Tree and graph algorithms Algorithms - sorting • • • • • • Insertion Bubble Quick sort Merge sort Counting sort Heap sort Algorithms • Time complexity • Memory complexity Text algorithms • • • • KMP Naive Boyer Moore Aho-Corasick Text algorithms • Regular expressions • Network intrusion • Databases Object oriented programming • Object languages: - Java (business applications, mobile software etc.) - C++ (embedded, real-time, financesector) - Python (prototyping, testing) - Smalltalk - Ruby (web) - Objective-C (mobile) -… Object oriented programming • programming paradigm - data structures called "objects", contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods. Object oriented programming • a feature of objects is that an object's procedures can access and often modify the data fields of the object with which they are associated, • in OO programming, objects in a software system interact with one another. Object oriented programming • There is significant diversity in object-oriented programming, but most popular languages are class-based, meaning that objects are instances of classes, which typically also determines their type. Object oriented programming Languages that support object-oriented programming use inheritance for code reuse and extensibility in the form of either classes or prototypes. Those that use classes support two main concepts: • Objects - structures that contain both data and procedures • Classes - definitions for the data format and available procedures for a given type or class of object; may also contain data and procedures (class methods) Object oriented programming • Objects sometimes correspond to things found in the real world (e.g. a graphics program may have objects such as „figure ", "circle ", "square" or " cursor ", online shop may have objects such as "shopping cart" "customer" " basket " or "product ", • Objects can represent more abstract things and entities, like an object that represents an open file, or an object which provides some service (e.g. xml parsing) Object oriented programming Object is an instance of a particular class. Procedures in objectoriented programming are known as methods, variables are also known as fields, members, attributes or properties. • Class variables - belong to the class as a whole; there is only one copy of each one • Instance variables or attributes - data that belongs to individual objects; every object has its own copy of each one • Member variables - refers to both the class and instance variables that are defined by a particular class • Class methods - belong to the class as a whole and have access only to class variables and inputs from the procedure call • Instance methods - belong to individual objects, and have access to instance variables for the specific object they are called on, inputs, and class variables Class definition class TComplex { private: double fRe; double fIm; // the real part // the imaginary part public: // Getters / Setters double GetRe( void ) const { return fRe; } double GetIm( void ) const { return fIm; } void SetRe( double re ) { fRe = re; } void SetIm( double im ) { fIm = im; } }; Class definition public class Complex { private double fRe; private double fIm; public void setRe(double re) {fRe = re;} public void setIm(double im) {fIm = im;} public double getRe() {return fRe;} public double getIm() {return fIm;} } Definicja klasy public class Complex { private double fRe; private double fIm; public void setRe(double re) {fRe = re;} public void setIm(double im) {fIm = im;} public double getRe() {return fRe;} public double getIm() {return fIm;} public static void length(Complex c) { … } } Object oriented programming • „Pure" OO languages, because everything in them is treated consistently as an object, from primitives such as characters and punctuation, all the way up to whole classes, prototypes, blocks, modules, etc. Examples: Eiffel, Obix, Ruby, Scala, Smalltalk, Self. • Languages designed mainly for OO programming, but with some procedural elements. Examples: Delphi/Object Pascal, C++, Java, C#, VB.NET. • Languages that are historically procedural languages, but have been extended with some OO features. Examples: Pascal, Visual Basic (derived from BASIC), Perl, COBOL 2002, PHP, Ada 95. • Languages with abstract data type support but without all features of object-orientation. This includes object-based and prototypebased languages. Examples: Modula-2, JavaScript, Lua. • Chameleon languages that support multiple paradigms, including OO, hybrid object system that supports both prototype-based programming and class-based OO (Tcl). Object oriented programming • • • • • Dynamic dispatch/message passing Inheritance Polymorphism Abstraction Encapsulation Dynamic dispatch/message passing • by definition, it is the responsibility of the object, to 'on-demand' select the procedural code to run/execute in response to a method call, by looking up the method at run time in a table associated with the object, • multiple dispatch - if there are multiple methods that might be run for a given name (this process require some language support). Objects and methods invocation int main() { TComplex a, b, c; TComplex d( 10, 20 ); std::cout << c.GetRe() << std::endl; std::cout << d.GetRe() << std::endl; } Constructors - arrays #include <iostream> using namespace std; class Box { public: Box() { cout << "Constructor called!" <<endl; } ~Box() { cout << "Destructor called!" <<endl; } }; int main( ) { Box* myBoxArray = new Box[4]; delete [] myBoxArray; // Delete array return 0; } Constructors - arrays Constructor called! Constructor called! Constructor called! Destructor called! Destructor called! Destructor called! Objects and methods invocation public static void main(String[] args) { Complex a = new Complex(); Complex c = new Complex(10, 20); System.out.println(c.fRe); } Composition • Objects can contain other objects in their instance variables, • For example, an object in the Employee class might contain (point to) an object of the Address class, in addition to its other own instance variables, • Object composition is used to represent "has-a" relationships: every employee has an address, so every Employee object has a place to store an Address object. Composition class Address { private: std::string street; std::string city; int houseNumber; … }; class Employee { private: std::string name; Address address; … }; Composition public class Address { private String street; private String city; private int houseNumber; } public class Employee { private String name; private Address address; } Inheritance • Languages that support classes almost always support inheritance. • This allows classes to be arranged in a hierarchy that represents "isa-type-of" relationships. • For example, class Employee might inherit from class Person. All the data and methods available to the parent class also appear in the child class with the same names. • For example, class Person might define variables "first_name" and "last_name" with method "make_full_name()". These will also be available in class Employee, and with additional variables "position" and "salary". • This technique allows easy re-use of the same procedures and data definitions, with similar real-world relationships, Inheritance public class Person { protected String first_name; protected String last_name; public String make_full_name() { return first_name+last_name; } } public class Employee extends Person { private String position; private int salary; } Inheritance class Person { protected: std::string first_name; std::string last_name; public: std::string make_full_name() { return first_name+last_name; } }; class Employee: public Person { private: std::string position; int salary; }; Inheritance • Subclasses can override the methods defined by superclasses. • Multiple inheritance is allowed in some languages (this can make resolving overrides complicated), • Some languages have special support for mixins, though in any language with multiple inheritance, a mixin is simply a class that does not represent an is-a-type-of relationship. Mixins are typically used to add the same methods to multiple classes. For example, class UnicodeConversionMixin might provide a method unicode_to_ascii() when included in class FileReader and class WebPageScraper, which don't share a common parent. Overriding public class Employee extends Person { protected String position; protected int salary; public String make_full_name() { return last_name; } } Overriding class Employee: public Person { protected: std::string position; int salary; public: std::string make_full_name() { return last_name; } }; Overloading public class Employee extends Person { private String position; private int salary; public String make_full_name(int parameter) { return last_name; } } Inheritance • Abstract classes cannot be instantiated into objects, they exist only for the purpose of inheritance into other classes which can be instantiated (not abstract). In Java, the final keyword can be used to prevent a class from being subclassed. • The "open/closed principle" - classes and functions "should be open for extension, but closed for modification". Abstract classes public abstract class Figure { protected int position; protected String name; public void draw() { } public String getName() { return name; } } Abstract Class class Figure { protected: std::string name; int position; public: virtual void draw() { } virtual std::string getName() { } }; Inheritance vs Composition • The doctrine of composition over inheritance advocates implementing is-a-type-of relationships using composition instead of inheritance. • For example, instead of inheriting from class Person, class Employee could give each Employee object an internal. Some languages, do not support inheritance at all. Encapsulation • If a class disallows calling code from accessing internal object data and forces access through methods only, this is a strong form of abstraction or information hiding known as encapsulation. • Some languages (Java, C++ for example) let classes enforce access restrictions explicitly, for example denoting internal data with the private keyword and designating methods intended for use by code outside the class with the public keyword. • Methods may also be designed public, private, intermediate levels such as protected (which typically allows access from other objects of the same class, but not objects of a different class) or default. Encapsulation • This facilitates code refactoring, for example allowing the author of the class to change how objects of that class represent their data internally without changing any external code, • Encourages programmers to put all the code that is concerned with a certain set of data in the same class, which organizes it for easy comprehension by other programmers. • Encapsulation is often used as a technique for encouraging decoupling. Polymorphism • Subtyping, a form of polymorphism, is when calling code can be agnostic as to whether an object belongs to a parent class or one of its descendants. For example, a function might call "make_full_name()" on an object, which will work whether the object is of class Person or class Employee. This is another type of abstraction which simplifies code external to the class hierarchy. • In languages that support open recursion, object methods can call other methods on the same object (including themselves), typically using a special variable or keyword called this or self. It allows a method defined in one class to invoke another method that is defined later, in some subclass Polymorphism (java example) Person p = new Employee("Nowak", "Jerzy"); System.out.println(p.make_full_name()); Polymorphism (C++) • Static linkage (binding) • Dynamic linkage (binding) Polymorphism (C++) virtual int area() { cout << "Parent class area :" <<endl; return 0; } virtual int area() = 0; Polymorphism (C++) class Figure { protected: int width, height; public: Figure( int a=0, int b=0) { width = a; height = b; } virtual int area() { cout << "Parent class area :" <<endl; return 0; } }; class Rectangle: public Figure { public: Rectangle( int a=0, int b=0):Shape(a, b) { } int area () { cout << "Rectangle class area :" <<endl; return (width * height); } }; Polymorphism (C++) Figure *shape; Rectangle rec(10,7); shape = &rec; shape->area(); Object life cycle • creation (constructors) • state changes of object • removal (destructor) Keyword const int a = 0; const int b = 1; a = 10; // b=11; Error! class example { public: void funkcja_1(void) const; void funkcja_2(); ... }; int main() { example a; const example b; a.funkcja_1(); b.funkcja_1(); a.funkcja_2(); // b.funkcja_2(); Error! } Initialization - constructors • • • • default parameterized copying (C++) if defined constructor by programmer no defult constructor (must be redefined) • no return values Constructors • defined constructors can be public (most popular, public classes), protected, private (hardly ever e.g. in Singleton pattern, private classes) Constructor (not parametrized) Complex( void ) : fRe( 0.0 ), fIm( 0.0 ) { } Constructor (with parameters) Complex( double re, double im ) : fRe( re ), fIm( im ) {} Complex( double re, double im ) { fRe = re; fIm = im; } Complex( double re) : fRe( re ) {} Copy constructor Complex( const Complex & c ) : fRe( c.fRe ), fIm( c.fIm ) {} Utilization: function parameters, initialization of object by other object Copy constructor Complex c(10.0, 1.0); Complex d = c; Sequence of constructor execution • base object-> derivative Example: class Figure { private: int x; int y; std::string name; public: Figure() { cout << "figure default" << endl; } Figure(int _x, int _y) : x(_x), y(_y) { cout << "figure" << endl; } void rysuj() {} }; Constructors class Square: public Figure { private: int color; int width; public: Square(int _x, int _y, int c) : Figure(_x, _y), color(c) { cout << "square" << endl;} Square(int c) : color(c) { cout << "square" << endl;} }; int main() { Square s1(1, 2, 10); Square s2(10); } Objects removing • Destructors (C++) ~Complex() {} • Garbage collector (Java) Destructor invocation • By operator delete (dynamic objects) • At the end of block (static objects) Sequence of destructor execution ~Figure() { cout << "figure deallocate" << endl; } ~Square() { cout << "square deallocate" << endl; } int main() { Square * s = new Square(1,2,10); delete s; } Destructors ~Complex() { std::cout << "destroyed" << std::endl; } main() { … Complex* complex = new Complex(10.0, 1.0); Complex c(10.0, 1.0); … delete complex; } Object oriented programming class TComplex { private: double fRe; double fIm; // the real part // the imaginary part public: /////////////////////////////////////////////////////////// // The class constructors /////////////////////////////////////////////////////////// TComplex( void ) : fRe( 0.0 ), fIm( 0.0 ) { } TComplex( double re, double im ) : fRe( re ), fIm( im ) {} TComplex( const TComplex & c ) : fRe( c.fRe ), fIm( c.fIm ) {} // copy constructor // Getters / Setters double GetRe( void ) const { return fRe; } double GetIm( void ) const { return fIm; } void SetRe( double re ) { fRe = re; } void SetIm( double im ) { fIm = im; } ~TComplex() {} }; Operator this void SetRe( double re ) { this->fRe = re; } void SetIm( double im ) { this->fIm = im; } C++ inheritance public – dziedziczenie pól publicznych jako publiczne, prywatnych jako prywatne, chronionych jak chronione C++ inheritance protected - dziedziczenie pól publicznych jako chronione, prywatnych jako prywatne, chronionych jak chronione C++ inheritance private - dziedziczenie pól publicznych jako prywatnych, prywatnych jako prywatne, chronionych jak prywatne Multi inheritance example: class Drawable { void rysuj() {} }; class Figure { private: int x; int y; std::string name; public: Figure() { cout << "figure default" << endl; } Figure(int _x, int _y) : x(_x), y(_y) { cout << "figure" << endl; } void rysuj() {} }; Multi inheritance class Square: public Figure , Drawable{ private: int color; int width; public: Square(int _x, int _y, int c) : Figure(_x, _y), color(c) { cout << "square" << endl;} }; int main() { Square s; s.rysuj(); //błąd } Java – Multi inheritance interface Drawable { } public class Figure { } public class Square extends Figure implements Drawable { } Overloading operators Complex & operator = ( const Complex & c ) { if( this != & c ) // check for a conditions such as: a = a { fRe = c.fRe; // if not the same, then fIm = c.fIm; // copy element by element } return * this; } Overloading operators Complex c(10.0, 1.0); Complex d; d = c; cout << d.GetRe() << ", " << d.GetIm() << endl; Overloading operators Complex & operator = ( const Complex & c ) { if( this != & c ) // check for a conditions such as: a=a { fRe = c.fRe; // if not the same, then fIm = c.fIm; // copy element by element } return * this; } Overloading operators bool operator == ( const TComplex & c ) const { return fRe == c.fRe && fIm == c.fIm; } TComplex operator + ( const TComplex & second_op ) const { TComplex retComplex( fRe + second_op.fRe, fIm + second_op.fIm ); return retComplex; } Overloading operators std::istream & operator >> ( std::istream & i, TComplex & complex) { double re, im; i >> re; i >> im; complex.SetRe( re ); complex.SetIm( im ); return i; } std::ostream & operator << ( std::ostream & o, TComplex & complex) { o << complex.GetRe() << ", " << complex.GetIm(); return o; } Template (szablon) C++ functionality for creating code independent from data types and algorithms. • function templates • class templates Template template <class T> class List { ... }; List <int> list; List <std::string> list; List <Element> list; Template (szablon) #include <iostream> #include <string> using namespace std; template <typename T> T const& Max (T const& a, T const& b) { return a < b ? b:a; } int main () { int i = 39; int j = 20; cout << "Max(i, j): " << Max(i, j) << endl; double f1 = 13.5; double f2 = 20.7; cout << "Max(f1, f2): " << Max(f1, f2) << endl; return 0; } Template template <class T> class Stack { private: vector<T> elems; // elements public: void push(T const&); // push element void pop(); // pop element }; template <class T> void Stack<T>::push (T const& elem) { elems.push_back(elem); } template <class T> void Stack<T>::pop () { elems.pop_back(); } Template int main() { Stack<int> intStack; // stack of ints Stack<string> stringStack; // stack of strings intStack.push(7); stringStack.push("hello"); } Java - generic • Generic methods • Generic classes Generic method public class GenericMethodTest { public static < E > void printArray( E[] inputArray ) { for ( E element : inputArray ) { System.out.printf( "%s ", element ); } System.out.println(); } public static void main( String args[] ) { Integer[] intArray = { 1, 2, 3, 4, 5 }; Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 }; Character[] charArray = { 'H', 'E', 'L', 'L', 'O' }; System.out.println( "Array integerArray contains:" ); printArray( intArray ); System.out.println( "\nArray doubleArray contains:" ); printArray( doubleArray ); System.out.println( "\nArray characterArray contains:" ); printArray( charArray ); } } Generic class public class Box<T> { private T t; public void add(T t) { this.t = t; } public T get() { return t; } public static void main(String[] args) { Box<Integer> integerBox = new Box<Integer>(); Box<String> stringBox = new Box<String>(); integerBox.add(new Integer(10)); stringBox.add(new String("Hello World")); System.out.printf("Integer Value :%d\n\n", integerBox.get()); System.out.printf("String Value :%s\n", stringBox.get()); }} Friend method • Nie jest ważne w którym miejscu klasy (private, protected, public) zostanie przyjaźo zadeklarowana. Przyjaźnie danej klasy są stosunkowo ważne z punktu widzenia projektanta, stąd też deklaracje przyjaźni zaleca się deklarowad na samym początku deklaracji klasy. • Przyjaźo nie jest dziedziczona. • Gdy istnieje wiele przeciążonych funkcji, funkcją zaprzyjaźnioną klasy jest tylko ta funkcja, która ma zgodną listę argumentów z zadeklarowaną funkcją zaprzyjaźnioną. • Funkcja może byd przyjacielem wielu klas. • Funkcją zaprzyjaźnioną może byd zarówno funkcja globalna, jak i funkcja składowa innej klasy. • Funkcja zaprzyjaźniona nie jest składnikiem klasy, która deklaruje przyjaźo. Friend class and method class A { friend void function( A& ); // deklaracja przyjaźni friend void B::function( A& ); // deklaracja przyjaźni funkcji składowej klasy B int attr; }; void fun( A& obiekt ) { obiekt.attr = 1; cout << obiekt.attr; } Exceptions 1) An exception is a problem that arises during the execution of a program 2) Response to an exceptional circumstance 3) Keywords: • throw - program throws an exception • try - try block identifies a block of code for which particular exceptions will be activated • catch - program catches an exception with an exception handler at the place in a program where you want to handle the problem Exceptions try { // protected code } catch( ExceptionName e1 ) { // catch block } catch( ExceptionName e2 ) { // catch block } catch( ExceptionName eN ) { // catch block } Exception - example double division(int a, int b) { if( b == 0 ) { throw "Division by zero condition!"; } return (a/b); } Exceptions - example int x = 50; int y = 0; double z = 0; try { z = division(x, y); cout << z << endl; } catch (const char* msg) { cerr << msg << endl; } Exceptions - example struct MyException : public exception { const char * what () const throw () { return "C++ Exception"; } }; int main() { try { throw MyException(); } catch(MyException& e) { std::cout << "MyException caught" << std::endl; std::cout << e.what() << std::endl; } catch(std::exception& e) { //Other errors } } Exceptions - example class MyException : public exception { public: const char * what () { return "C++ Exception"; } }; Exceptions - example try { throw MyException(); } catch(std::exception& e) { std::cout << "exception" << std::endl; } catch(MyException& e) { std::cout << "MyException caught" << std::endl; std::cout << e.what() << std::endl; } Exception Description std::exception An exception and parent class of all the standard C++ exceptions. std::bad_alloc This can be thrown by new. std::bad_cast This can be thrown by dynamic_cast. std::bad_exception This is useful device to handle unexpected exceptions in a C++ program std::bad_typeid This can be thrown by typeid. std::logic_error An exception that theoretically can be detected by reading the code. std::domain_error This is an exception thrown when a mathematically invalid domain is used std::invalid_argument This is thrown due to invalid arguments. std::length_error This is thrown when a too big std::string is created Exception Description std::out_of_range This can be thrown by the at method from for example a std::vector and std::bitset<>::operator[](). std::runtime_error An exception that theoretically can not be detected by reading the code. std::overflow_error This is thrown if a mathematical overflow occurs. std::range_error This is occured when you try to store a value which is out of range. std::underflow_error This is thrown if a mathematical underflow occurs. Static void func(void); static int count = 10; main() { while(count--) { func(); } return 0; } // Function definition void func( void ) { static int i = 5; // local static variable i++; std::cout << "i is " << i ; std::cout << " and count is " << count << std::endl; } Namespace namespace namespace_name { //code declarations } name::code; Input/output • iostream • fstream ifstream ofstream void open(const char *filename, ios::openmode mode); fstream afile; afile.open("file.dat", ios::out | ios::in ); // position to the nth byte of fileObject (assumes ios::beg) fileObject.seekg( n ); // position n bytes forward in fileObject fileObject.seekg( n, ios::cur ); // position n bytes back from end of fileObject fileObject.seekg( n, ios::end ); // position at end of fileObject fileObject.seekg( 0, ios::end ); Casting • • • • const cast static cast dynamic cast reinterpret cast Const cast Konwersja uzmienniająca ma postad • const_cast<Typ>(wyrazenie) • Wyrażenie wyrazenie musi tu byd tego samego typu co Typ, tylko z modyfikatorem const lub volatile. • Konwersja usuwa „ustalonośd” (lub „ulotnośd”) i może służyd tylko do tego celu. • W innych przypadkach const Typ → Typ nielegalne Static cast Konwersja statyczna ma postad • static_cast<Typ>(wyrazenie) dokonuje jawnego przekształcenia typu, sprawdzając, czy jest to przekształcenie dopuszczalne na etapie kompilacji. Często użycie tego operatora jest zbędne, bo konwersja i tak zostanie dokonana. double x = 4; int i = x; warning: initialization to `int' from `double' warning: argument to `int' from `double' możemy uniknąd jawnie dokonując konwersji: double x = 4; int i = static_cast<int>(x); Dynamic cast Konwersja dynamiczna ma postad • dynamic_cast<Typ>(wyrazenie) • Konwersje dynamiczne stosuje się, gdy prawidłowośd przekształcenia nie może byd sprawdzona na etapie kompilacji (zależy od typu obiektu klasy polimorficznej). • Typ ten jest znany dopiero w czasie wykonania i wtedy ma miejsce sprawdzenie poprawności. • Konwersje używane są wyłącznie w odniesieniu do klas polimorficznych i tylko dla typów wskaźnikowych i odnośnikowych Reinterpret cast „Najsilniejszą” formą konwersji jest konwersja wymuszana. Ma ona postad • reinterpret_cast<Typ>(wyrazenie) • Użycie takiej konwersji oznacza, że rezygnujemy ze sprawdzania jej poprawności w czasie kompilacji i wykonania (ponosimy pełną odpowiedzialnośd za jej skutki), • Stosuje się ją, gdy wiemy z góry, że ani w czasie kompilacji, ani w czasie wykonania nie będzie możliwe określenie jej sensowności, • Można, na przykład, dokonad konwersji char* → int* lub klasaA* → klasaB*, gdzie klasy klasaA i klasaB są zupełnie niezależne, takie konwersje nie są bezpieczne, Dynamic cast Operator dynamicznego rzutowania (konwersji) stosuje się, gdy prawidłowośd przekształcenia nie może byd sprawdzona na etapie kompilacji (zależy od typu obiektu klasy polimorficznej), który znany jest dopiero w czasie wykonania. Jego użycie ma sens w sytuacjach, gdy mamy do czynienia z obiektami różnych klas powiązanych ze sobą hierarchią dziedziczenia. Dynamic cast • dynamic_cast<Typ>(wyrazenie) Typ Typ jest typem wskaźnikowym do polimorficznej klasy pochodnej, czyli Typ = B*, a wartością wyrażenia wyrazenie jest wskazanie na obiekt klasy bazowej A, czyli wartośd o typie A*. Operacja rzutowania polega wtedy na sprawdzeniu, czy obiekt wskazywany przez wyrazenie jest w rzeczywistości obiektem klasy pochodnej B; po tym teście wartością całego tego wyrażenia staje się – wartośd wskaźnikowa typu B* wskazująca na obiekt wskazywany przez wyrazenie, jeśli test wypadł pomyślnie; – zero (wskaźnik pusty, NULL), jeśli test się nie powiódł, czyli obiekt wskazywany przez wyrazenie nie jest obiektem klasy B. Można to w programie sprawdzid odpowiednim if'em i podjąd stosowne działania bez przerywania programu. Dynamic cast Typ Typ jest typem referencyjnym do polimorficznej klasy pochodnej, czyli Typ = B&, a wartością wyrażenia wyrazenie jest l-nazwa obiektu klasy A. Operacja rzutowania polega wtedy na sprawdzeniu, czy obiekt wyrazenie jest w rzeczywistości obiektem klasy pochodnej B; po tym teście, – jeśli wypadł pomyślnie, wartością całego wyrażenia staje się odniesienie typu B& do obiektu wyrazenie; – jeśli wypadł niepomyślnie, bo obiekt wyrazenie nie jest typu B, to zgłaszany jest wyjątek typu bad_cast (z nagłówka typeinfo), który można przechwycid i podjąd stosowne działania bez przerywania programu. Tym razem nie można przekazad informacji o niepowodzeniu zerową wartością wyrażenia, bo nie ma czegoś takiego jak puste odniesienie (tak jak jest pusty, czyli zerowy, wskaźnik). Dlatego do obsługi tego przypadku wybrano metodę zgłoszenia wyjątku. Dynamic cast class Program { protected: string name; public: Program(string n) : name(n) { } virtual void print() = 0; virtual ~Program() { } }; class Freeware : public Program { public: Freeware(string n) Program(n) { } void print() { cout << "Free : " << name << endl; } }; Dynamic cast class Shareware : public Program { int price; public: Shareware(string n, int c) : Program(n), price(c) { } void print() { cout << "Share: " << name << ", price " << price << endl; } int getPrice() { return price; } }; Dynamic cast int total(Program* prgs[], int size) { Shareware* sh; int tot = 0; for (int i = 0; i < size; ++i) { prgs[i]->print(); if ( sh = dynamic_cast<Shareware*>(prgs[i])) tot += sh->getPrice(); } return tot; } Dynamic cast int main(void) { Freeware mongodb(„mongodb"); Shareware wz("WinZip",30); Freeware mysql("MySQL"); Shareware rar("RAR",25); Program* prgs[] = { &mongodb, &wz, &mysql, &rar }; int tot = total(prgs, sizeof(prgs)/sizeof(prgs[0])); cout << "\nTotal: $" << tot << endl; }