Wykład 4
Transkrypt
Wykład 4
Object oriented languages dr inż. Marcin Pietroo 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. Exceptions terminate called after throwing an instance of 'std::out_of_range' what(): vector::_M_range_check 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) 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; } Dynamic cast (reference) int total(Program* prgs[], int size) { int tot = 0; for (int i = 0; i < size; ++i) { prgs[i]->print(); try { Shareware& sh = dynamic_cast<Shareware&>(*prgs[i]); tot += sh.getPrice(); } catch(bad_cast) { } } return tot; } Reinterpret_cast char* buff1 = new char[size]; reinterpret_cast<char*>(&person_object); Person* p1 = reinterpret_cast<Person*>(buff1); References and pointers int * const z1 = &i; z1 = &j; *z1 = *z1 + 10; References and pointers int x = 10; int &x_ref = x; x = 12 x_ref = 12; int *x_ptr = &x; *x_ptr = 12; References and pointers int &x_ref; int &x_ref = 10; const int &w = 10; int x = 10; int &x_ref = x; int && x_ref_ref = x_ref; References and pointers • access to element without copy • reference must be initiated during declaration • reference to variable is actual during whole program • reference can’t be multidimensional References and pointers Difference between: - const type * identifier - type const* identifier Task Implementation of vector and list classes