Programowanie obiektowe w C++

Slides:



Advertisements
Podobne prezentacje
C++ wykład 9 ( ) Szablony.
Advertisements

C++ wykład 2 ( ) Klasy i obiekty.
C++ wykład 4 ( ) Przeciążanie operatorów.
Język C/C++ Funkcje.
Programowanie obiektowe
Deklaracje i definicje klas w C++ Składowe, pola, metody Konstruktory
Klasa listy jednokierunkowej Przekazywanie parametrów do funkcji
Programowanie obiektowe
Programowanie obiektowe PO PO - LAB 4 Wojciech Pieprzyca.
Standardowa biblioteka języka C++
Programowanie obiektowe
Wzorce.
Zaawansowane metody programowania – Wykład V
Static, const, volatile.
Dziedziczenie. Po co nam dziedziczenie? class osoba { char * imie, char * imie, * nazwisko; * nazwisko;public: void wypisz_imie(); void wypisz_imie();
Programowanie w środowisku sieciowym
Programowanie obiektowe w Javie
Szablony (wzorce) Przykład 1: Szablon klasy -
Licznik template<class Count_Type> class Count { public:
Serwery Aplikacji ASP .NET Web Objects Arkadiusz Popa.
Struktury.
Dziedziczenie i jego rodzaje
C++ wykład 2 ( ) Klasy i obiekty.
Zasady zaliczenia Warunki uzyskania zaliczenia:
Języki programowania obiektowego
Wstęp do programowania obiektowego
Podstawy programowania II
T: Różnice pomiędzy programowaniem strukturalnym a obiektowym
Źródła: podręcznikopracował: A. Jędryczkowski.
Programowanie strukturalne i obiektowe
Jakub Wołczko W obiektowym świecie… Jakub Wołczko
Programowanie obiektowe III rok EiT
Programowanie obiektowe III rok EiT
Andrzej Repak Nr albumu
Java – coś na temat Klas Piotr Rosik
Dziedziczenie Maciek Mięczakowski
Inicjalizacja i sprzątanie
Programowanie obiektowe Wykład 3 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21 Dariusz Wardowski.
Programowanie obiektowe Wykład 7 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/20 Dariusz Wardowski.
Programowanie obiektowe Wykład 6 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14 Dariusz Wardowski.
Warsztaty C# Część 6 Grzegorz Piotrowski Grupa .NET PO
Programowanie obiektowe – język C++
Programowanie obiektowe 2013/2014
Prasek Aneta, Skiba Katarzyna. Funkcje stałe const to takie funkcje, które nie mogą modyfikować stanu obiektu. Oznacza to, że funkcja stała nie może zmieniać.
Kurs języka C++ – wykład 3 ( )
Kurs języka C++ – wykład 9 ( )
Programowanie w języku C++
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
K URS JĘZYKA C++ – WYKŁAD 10 ( ) Szablony.
Programowanie strukturalne i obiektowe C++
Kurs języka C++ – wykład 4 ( )
K URS JĘZYKA C++ – WYKŁAD 2 ( ) Klasy i obiekty.
Klasy ( uzupełnienie ). Definicja klasy Klasa jest zbiorem logicznie powiązanych danych i funkcji, przeznaczonych do realizacji konkretnego zadania; Zamknięcie.
Programowanie obiektowe Wykład 9 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/15 Dariusz Wardowski.
Paweł Starzyk Obiektowe metody projektowania systemów
Programowanie Zaawansowane
Dziedziczenie Wykład 7 Dziedziczenie sekwencyjne
Wykład 4 Klasa Vec, której konstruktory alokują pamięć dla obiektów 1.Przykład definicji klasy Vec 2.Definicje konstruktorów i destruktora 3.Definicja.
PO13-1 / 19 Wykład 13 Wyjątki i ich zgłaszanie Wyłapywanie wyjątków Obsługa wyjątków Wykorzystanie polimorfizmu Filtrowanie wyjątków Błędy w konstruktorach.
Partnerstwo dla Przyszłości 1 Lekcja 27 Klasy i obiekty.
Partnerstwo dla Przyszłości 1 Lekcja 28 Dziedziczenie i rodzaje dziedziczenia.
K URS JĘZYKA C++ – WYKŁAD 3 ( ) Przenoszenie Składowe statyczne Funkcje wbudowane Argumenty domyślne.
C++ mgr inż. Tomasz Turba Politechnika Opolska 2016.
Programowanie Obiektowe – Wykład 6
Kurs języka C++ – wykład 3 ( )
Klasy, pola, obiekty, metody. Modyfikatory dostępu, hermetyzacja
Programowanie Obiektowe – Wykład 2
Język C++ Typy Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego.
Zapis prezentacji:

Programowanie obiektowe w C++ Paweł Jarzyński Artur Pacholec

Definicja programowania obiektowego Programowanie obiektowe (nazywane też zorientowanym obiektowo) to paradygmat programowania w którym programy są definiowane za pomocą struktur łączących stan i zachowanie pewnych bytów przetwarzanych w trakcie działania programu. Stan jest reprezentowany za pomocą zmiennych natomiast zachowanie definiują metody. Struktury łączące stan i zachowanie nazywane są klasami i stanowią wzorzec na podstawie którego tworzone są unikalne byty zwane obiektami.

Historia obiektowych języków programowania Koncepcja programowania obiektowego pojawiła się w języku Simula 67 i miała być rozwiązaniem problemu opanowania wszystkich zależności pomiędzy danymi i operacjami których pogrupowanie pomogło zapanować nad skomplikowanymi programami symulacyjnymi. Pierwszym w pełni obiektowym językiem programowania był Smalltalk który powstał w latach 70 i był wzorem dla języka C++ którego popularność spowodowała, że w latach 80 programowanie obiektowe stało się techniką dominującą aż do dnia dzisiejszego. W latach 90 pojawił się obiektowy język Java, a niedługo później Microsoft stworzył wzorowany na nim język C#.

Podstawowe cechy języków obiektowych Abstrakcja pozwala tworzyć intuicyjny interfejs programistyczny umożliwiający odczyt i modyfikację stanu bytów (obiektów) bez bezpośredniego dostępu do danych które ten stan opisują. Hermetyzacja (zwana też czasem enkapsulacją) ogranicza bezpośredni dostęp do danych obiektu i podprogramów, które na nich operują, w celu uniemożliwienie wykonania niedozwolonych operacji. Dziedziczenie umożliwia definiowanie nowych typów (klas), w oparciu o te już wcześniej definiowanie, co tworzy model hierarchiczny zwany drzewem dziedziczenia. Polimorfizm to mechanizm dynamicznego wiązania właściwego zachowania z bytem (obiektem) utworzonym na podstawie konkretnego wzorca (klasy) w hierarchii dziedziczenia.

Pojęcie klasy i obiektu Klasa (nazywana często typem) definiuje dane (zmienne) oraz zachowanie (podprogramy) bytów i stanowi wzorzec na podstawie którego powoływane są do życia konkretne ich egzemplarze zwane obiektami. Zmienne zdefiniowane w klasie nazywane są polami a podprogramy na nich operujące metodami klasy. Obiekt (nazywany często instancją klasy) jest unikalnym bytem skonstruowanym w oparciu o konkretną klasę, posiadającym stan reprezentowany przez unikalną dla siebie grupę danych jakie w sobie skupia. Obiekt jest dostępny poprzez zmienną lub wskaźnik/referencję która na niego wskazuje. Odczyt i modyfikacja jego stanu jest możliwa poprzez bezpośrednie odwołanie się do jego pól lub za pośrednictwem metod zdefiniowanych w klasie której dany obiekt jest egzemplarzem.

Definiowanie klasy W języku C++ można definiować klasy na dwa sposoby, różniące się miejscem implementacji metod: implementacja razem z definicją klasy rozdzielenie implementacji i definicji

Implementacja z definicją class Matrix { private: int n, m; double **numbers; public: Matrix(int n, int m) { ... } ~Matrix() { double det() { double get(int i, int j) { return numbers[i][j]; };

Rozdzielona definicja i implementacja Część nagłówkowa (plik *.h) Część implementacyjna (plik *.cpp) class Matrix { private: int n, m; double **numbers; public: Matrix(int, int); ~Matrix(); double det(); double get(int, int); }; Matrix::Matrix(int n, int m) { ... } Matrix::~Matrix() double Matrix::det() double Matrix::get(int i, int j) return numbers[i][j];

Zmienna this Zmienna this używana w ciele metod przechowuje zawsze adres obiektu na rzecz którego metoda będzie wywołana. class Matrix { private: int n, m; double **numbers; public: double get(int i, int j) return this->numbers[i][j]; } };

Pola i metody stałe Pola z modyfikatorem const są przeznaczone tylko do odczytu. Metody const nie mogą zmieniać stanu obiektu czyli nie mogą modyfikować pól ani wywoływać innych metod które nie są stałe. class Matrix { private: const int n, m; double **numbers; public: double get(int i, int j) const return this->numbers[i][j]; } };

Obiekty stałe Obiekty const służą tylko do odczytu ich stanu, bez możliwości jego zmiany, czyli nie można modyfikować ich pól, ani wywoływać metod które nie są stałe. const Matrix mcHammer; //can’t touch this Pola mutable mogą być modyfikowane przez metody stałe lub gdy stały jest cały obiekt. class A { private: int x, y; mutable int tmp; public: int exec() const // można modyfikować pole tmp } };

Pola statyczne Pola statyczne należą do klasy i nie są unikalne dla każdego z jej obiektów (czyli są globalne). class A { public: static int a; int b; }; Ponieważ pola statyczne należą do klasy, nie są alokowane wraz z jej obiektami i dlatego wymagają definicji poza klasą (ponieważ klasa zawiera tylko deklarację pól). int A::a; //w .cpp

Metody statyczne Metody statyczne nie mogą używać zmiennej this ponieważ nie są wywoływane na rzecz istniejącego obiektu. class A { public: static int f() ... } }; A::f(); A a; a.f();

Różnice między podejściem obiektowym i proceduralnym struct Stack { Node* top; int size; }; void init(Stack* stack); void destroy(Stack* stack); void push(Stack* stack, int value); int pop(Stack* stack); class Stack { private: Node* top; int size; public: Stack(); ~Stack(); void push(int value); int pop(); };

Konstruktory i destruktory Konstruktor jest specjalną metodą wywoływaną automatycznie podczas tworzenia nowego obiektu. Destruktor również jest specjalną metodą wywoływaną automatycznie podczas niszczenia obiektu.

class Matrix { private: int n, m; double class Matrix { private: int n, m; double **numbers; public: Matrix(int n, int m) this->n = n; this->m = m; numbers = new double*[n]; for(int i = 0; i < n; ++i) numbers[i] = new double[m]; } ~Matrix() delete[] numbers[i]; delete[] numbers; };

Konstruktory i destruktory II Klasa może posiadać wiele konstruktorów różniących się typami pobieranych parametrów lub ich ilością (domyślnie konstruktor jest bezargumentowy i nie trzeba go definiować). Klasa może posiadać dokładnie jeden destruktor który nie pobiera żadnych argumentów (nie trzeba go definiować jeśli nie ma takiej potrzeby). class Matrix { public: Matrix(int n); Matrix(int n, int m); Matrix(int n, int m, double value); ~Matrix(); };

Konstruktor kopiujący Gdy nowo tworzony obiekt jest inicjalizowany już istniejącym lub gdy obiekt jest przekazany jako argument do funkcji czy metody, tworzona jest jego kopia. Domyślnie tworzona jest kopia nazywana płytką kopią, która przepisuje wartości wszystkich pól klasy. Może to nie wystarczyć gdy obiekty operują na złożonych danych, alokowanych dynamicznie, ponieważ wartościami pól są wtedy adresy, a nie dane które się pod nimi znajdują. Kopia całego obiektu wraz z dynamicznie zaalokowanymi danymi, z którymi jest powiązany nazywana jest kopią głęboką i wymaga utworzenia konstruktora kopiującego.

class Matrix { private: int n, m; double class Matrix { private: int n, m; double **numbers; public: Matrix(int n, int m); Matrix(const Matrix& matrix) n = matrix.n; m = matrix.m; numbers = new double*[n]; for(int i = 0; i < n; ++i) { numbers[i] = new double[m]; for(int j = 0; j < m; ++j) numbers[i][j] = matrix.numbers[i][j]; } ~Matrix(); };

Lista inicjalizacyjna konstruktora Lista inicjalizacyjna jest wygodnym sposobem na czytelne oddzielenie części konstruktora której zadaniem jest nadanie polom wartości, od tej która wykonuje bardziej złożone operacje na tych polach w celu przygotowania obiektu do stanu użyteczności. Matrix::Matrix(int n, int m): n(n), m(m) { numbers = new double*[n]; for(int i = 0; i < n; ++i) numbers[i] = new double[m]; }

Lista inicjalizacyjna konstruktora II Jeśli klasa zawiera referencje, pola stałe albo takie które są obiektami innej klasy, nie posiadającej konstruktora bezargumentowego, to utworzenie takiej listy jest obowiązkowe. class A { private: const double x; double& y; Matrix matrix; public: A(const double valueX, double& valueY, int n, int m): x(valueX), y(valueY), matrix(n, m) { } }; POŁOWA!!

Abstrakcja danych Abstrakcja umożliwia opakowywanie danych oraz algorytmów które te dane przetwarzają w klasy i dostarczenie programiście pewnego interfejsu przy pomocy którego będzie mógł przetwarzać obiekty bez znajomości szczegółów implementacyjnych algorytmów które za pośrednictwem tego interfejsu uruchamia. list.last() list.sort() matrix.det() matrixA * matrixB

Hermetyzacja Hermetyzacja pozwala sterować dostępem do danych lub metod które nie powinny być przetwarzane "na zewnątrz" w sposób bezpośredni. Podstawowe modyfikatory dostępu jakie można spotkać w obiektowych językach programowania to public, protected oraz private. class A{ private: // składowe prywatne protected: // składowe chronione public: // składowe publiczne };

Akcesory i modyfikatory Deklaracja pól (nawet tych które mają być dostępne do odczytu i modyfikacji) w sekcji publicznej niesie ze sobą ryzyko, że mogą one zostać zmodyfikowane "na zewnątrz" obiektu w niewłaściwy sposób który zaburzy działanie programu lub nawet uniemożliwi dalsze jego wykonywanie. Sposobem na wyeliminowanie tego ryzyka jest deklaracja wszystkich pól obiektu w sekcji prywatnej i utworzenie metod przeznaczonych do odczytu i modyfikacji wartości tych pól w sposób kontrolowany.

class A{ private: double x; public: double getX() const; void setX(double); }; inline double A::getX() const{ return x; } inline void A::setX(double value){ if(value >= 0.0 && value <= 1000.0) x = value;

Klasy i funkcje zaprzyjaźnione Czasem zachodzi potrzeba utworzenia wyjątków od nałożonych przez hermetyzację barier i umożliwienia dostępu do wszystkich składowych konkretnej klasie lub funkcji. Aby naruszyć hermetyzację i umożliwić dostęp do wszystkich składowych niezależnie od sekcji w jakiej zostały zadeklarowane należy użyć deklaracji friend. class A{ private: double x[2], y[2]; friend double f(const A&); }; double f(const A& a){ return a.x[0] * a.y[0] + a.x[1] * a.y[1]; }

class Node{ private: int value; Node(int value): value(value){} friend class List; }; class List{ Node* head; Node* tail; int size; public: List(): head(NULL), tail(NULL), size(0){} ...

Kompozycja Kompozycją nazywamy strukturę danych w której polami jednej klasy są obiekty lub kolekcje obiektów innej klasy. class A{ ... }; class B{ class C{ A a; list<B> bList; class D{ C c1, c2;

class Punkt{ double x, y; }; class Bron{ int sila; ... class Postac{ Punkt pozycja; int poziomZdrowia; list<Bron*> bronie; class Budynek{ int wytrzymalosc; class Plansza{ list<Bron> dostepneBronie; list<Postac> postacie; list<Budynek> budynki;

Dziedziczenie Dziedziczenie pozwala na definiowane nowych klas w oparciu o już zdefiniowane rozszerzając tym samym ich funkcjonalność. Klasa która w swojej definicji dziedziczy po już zdefiniowanej otrzymuje wszystkie jej pola oraz dostęp do niektórych pól oraz metod. Dostęp do odziedziczonych składowych można dodatkowo ograniczyć przy pomocy znanych modyfikatorów.

class A{ private: int a; void f(){. } protected: int b; void g(){ class A{ private: int a; void f(){...} protected: int b; void g(){...} public: int c; void h(){...} }; class B: public A{ public: int d, e; void h(){ A::h(); ... } void f2(){...} };

class Punkt{ double x, y; }; class Tekstura{ class Punkt{ double x, y; }; class Tekstura{ ... class Obiekt{ Punkt pozycja; Tekstura tekstura; class ObiektNieruchomy: public Obiekt{ class Budynek: public ObiektNieruchomy{ class Roslina: public ObiektNieruchomy{ class ObiektRuchomy: public Obiekt{ int predkoscMaksymalna; ... }; class Pojazd: public ObiektRuchomy{ int poziomPaliwa; class Postac: public ObiektRuchomy{ int poziomZdrowia; list<Born*> bronie;

Wielodziedziczenie Niektóre języki (w tym C++) pozwalają na dziedziczenie po kilku klasach jednocześnie co nazywa się wielodziedziczeniem. class A{ public: int x; }; class B{ double x; class C: public A, public B{ ... C c; c.A::x; c.B::x;

Dziedziczenie a konstruktor Jeśli nadklasa nie posiada konstruktora bezargumentowego lub zajdzie potrzeba wywołania jej konstruktora z pewnymi argumentami to w definicji konstruktora klasy pochodnej należy użyć listy inicjalizacyjnej. class A{ protected: int x, y; public: A(int x, int y): x(x), y(y){} }; class B: public A{ ... B(int x, int y): A(x, y){}

Kolejność wywoływania a dziedziczenie Konstruktory są wywoływane począwszy od tego z klasy bazowej a skończywszy na konstruktorze klasy której obiekt jest tworzony. Podczas niszczenia obiektu destruktory są wywoływane w dokładnie odwrotnej kolejności.

Polimorfizm Polimorfizm jest mechanizmem dynamicznego wiązania wywołań metod z właściwym dla danego typu obiektu kodem tych metod. W języku C++ należy jawnie zadeklarować takie zachowanie dla metody o konkretnej nazwie za pomocą słowa kluczowego virtual. class A{ public: virtual void f(){...} }; class B: public A{ void f(){...} class C: public B{

Polimorfizm II Należy zauważyć, że możliwe jest przypisanie do wskaźnika typu A adresu obiektów jest podklasy B lub C. A* o1 = new A; o1->f(); A* o2 = new B; o2->f(); A* o3 = new C; o3->f(); Ta sama własność dotyczy również referencji. C c; A& o4 = c; o4.f();

class Obiekt{ Punkt pozycja; virtual bool przemiesc(Punkt nowaPozycja){ pozycja = nowaPozycja; return true; } }; class Pojazd: public Obiekt{ double spalanie; double poziomPaliwa; bool przemiesc(Punkt nowaPozycja){ if(poziomPaliwa < spalanie * odleglosc(pozycja, nowaPozycja)) return false; Obiekt::przemiesc(nowaPozycja); poziomPaliwa -= spalanie * odleglosc(pozycja, nowaPozycja); class Postac: public Obiekt{ int energia; list<Bron*> bronie; ... bool Plansza::zmienPozycje(Obiekt& obiekt, Punkt nowaPozycja){ if(pozycjaWolna(nowaPozycja)) return obiekt.przemiesc(nowaPozycja);

Klasy abstrakcyjne Metoda abstrakcyjna w danej klasie to taka której implementacja nie została jeszcze zdefiniowana (klasa zawiera tylko jej prototyp), ale wiadomo, że nastąpi to w co najmniej jednej z klas pochodnych. Klasa która zawiera przynajmniej jedną metodę abstrakcyjną (zadeklarowaną w taj klasie lub w jednej z klas po których dziedziczy, ale do tej pory nie zaimplementowaną) nazywana jest klasą abstrakcyjną i nie można tworzyć jej obiektów. Takie rozwiązanie ma sens jeśli metoda abstrakcyjna będzie również wirtualna bo wtedy można się nią posługiwać stosując wskaźniki albo referencje do klas które nie zawierają jeszcze jej implementacji dlatego każda metoda abstrakcyjna musi być również wirtualną. Ponieważ nie można tworzyć obiektów klas abstrakcyjnych to mamy pewność, że taki wskaźnik lub referencja będzie wskazywała na obiekt klasy w której wszystkie metody abstrakcyjne zostały odpowiednio zdefiniowane.

class Abstrakcyjna{ public: virtual void przetwarzaj() = 0; }; class A: public Abstrakcyjna{ void przetwarzaj(){ // przetwarzanie A } class B: public Abstrakcyjna{ // przetwarzanie B class C: public B{ // przetwarzanie C void przetwarzajObiekt(Abstrakcyjna& obiekt){ obiekt.przetwarzaj();

class Szyfr{ protected: virtual void szyfruj(const char class Szyfr{ protected: virtual void szyfruj(const char* tekstJawny, char* szyfrogram, int rozmiar) = 0; public: void szyfrujPlik(const char* nazwaPlikuWejsciowego, const char* nazwaPlikuWyjsciowego){ ifstream plikWejsciowy(nazwaPlikuWejsciowego, ifstream::binary); ofstream plikWyjsciowy(nazwaPlikuWyjsciowego, ofstream::binary); char buforTekstJawny[1024], buforSzyfrogram[1024]; while(true){ plikWejsciowy.read(buforTekstJawny, 1024); if(plikWejsciowy.gcount() == 0) break; int odczytano = plikWejsciowy.gcount(); szyfruj(buforTekstJawny, buforSzyfrogram, odczytano); plikWyjsciowy.write(buforSzyfrogram, odczytano); } plikWejsciowy.close(); plikWyjsciowy.close(); }; class SzyfrPodstawieniowy: public Szyfr{ private: void szyfruj(const char* tekstJawny, char* szyfrogram, int rozmiar){ ... class SzyfrStrumieniowy: public Szyfr{

Interfejsy Interfejsem nazywamy pewien zbiór metod które dana klasa musi posiadać aby mogła realizować z góry ustaloną funkcjonalność. W języku C++ interfejs utożsamia się z klasą abstrakcyjną która zawiera wyłącznie metody abstrakcyjne a do jego implementacji często wykorzystuje się wielodziedziczenie którego nie ma w językach Java, C# i PHP dlatego interfejsy są tam odrębnym elementem.

class BazaDanych{ public: virtual bool polacz() = 0; virtual bool dodaj(const Dane&) = 0; virtual Dane pobierz(string) = 0; virtual void rozlacz() = 0; }; class System{ private: BazaDanych& baza; ... System(BazaDanych& baza): baza(baza){ } class BazaSQL: public BazaDanych{ bool polacz(){...}; bool dodaj(const Dane& dane){...}; Dane pobierz(string zapytanie){...}; void rozlacz(){...};

Szablony Szablony (zwane inaczej polimorfizmem statycznym) pozwalają na pisanie kodu programu który operuje na danych bez podawania konkretnych typów tych danych co nazywa się programowaniem uogólnionym. template <typename T> class Matrix{ private: int n, m; T** numbers; public: Matrix(int, int); ~Matrix(); T det(); T get(int, int); void set(int, int, T); }; Matrix<float> a(3, 3); Matrix<double> b(3, 3); Matrix<long double> c(3, 3);

template <typename T> class Node{ private: T value; public: Node(T value): value(value){} T get() const{ return value; } void set(T value){ this->value = value; }; class Stack{ Node<T>* data; Stack(): data(NULL){} ~Stack(){...} T top(){...} void push(T value){...} void pop(){...} Stack<int> s; Stack<Matrix> s;

Przestrzenie nazw Przestrzenie nazw służą eliminacji potencjalnych konfliktów nazw identyfikatorów. namespace Moja{ class A{...}; class B{...}; } namespace Inna{ Moja::A aMoja; Inna::B bInna; using Moja::A; A aMoja; Inna::A aInna; using namespace Moja; B bMoja;

Wyjątki Mechanizm wyjątków pozwala przekazać sterowanie do odpowiedniego miejsca gdy zaistnieje sytuacja uniemożliwiająca dalsze wykonywanie programu. Matrix operator*(const Matrix& a, const Matrix& b){ if(a.m != b.n) throw domain_error("wymiary macierzy niezgodne"); Macierz c; // mnożenie macierzy return c; } try{ ... Matrix c = a * b; }catch(domain_error& e){ // obsługa wyjątku

Pytania? Przemyślenia? Chęć pójścia do domu? Dziękujemy za uwagę Pytania? Przemyślenia? Chęć pójścia do domu?