Programowanie w języku C++

Podobne dokumenty
TEMAT : KLASY DZIEDZICZENIE

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy WSKAŹNIKI KLASOWE

Język C++ Programowanie obiektowe

Przeciążanie operatorów

Wykład 5: Klasy cz. 3

Wykład 8: klasy cz. 4

Rozdział 4 KLASY, OBIEKTY, METODY

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Programowanie Obiektowo Zorientowane w języku C++ Klasy, pola, metody

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

PARADYGMATY PROGRAMOWANIA Wykład 3

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Podstawy Programowania Obiektowego

C++ Przeładowanie operatorów i wzorce w klasach

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Programowanie Obiektowe i C++

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 4. Karol Tarnowski A-1 p.

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Do czego służą klasy?

Programowanie obiektowe, wykład nr 6. Klasy i obiekty

Dziedziczenie jednobazowe, poliformizm

Do czego służą klasy?

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

Programowanie, część I

Programowanie obiektowe Wykład 3. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21

2. Klasy cz. 2 - Konstruktor kopiujący. Pola tworzone statycznie i dynamicznie - Funkcje zaprzyjaźnione - Składowe statyczne

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

KLASY cz.1. Dorota Pylak

Dziedziczenie. Streszczenie Celem wykładu jest omówienie tematyki dziedziczenia klas. Czas wykładu 45 minut.

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Podstawy Programowania Obiektowego

Wstęp do Programowania 2

Programowanie obiektowe

Programowanie komputerowe. Zajęcia 7

Język C++ umożliwia przeciążanie operatora, tzn. zmianę jego znaczenia na potrzeby danej klasy. W tym celu definiujemy funkcję o nazwie:

Programowanie II. Lista 3. Modyfikatory dostępu plik TKLientBanku.h

Programowanie w C++ Wykład 13. Katarzyna Grzelak. 4 czerwca K.Grzelak (Wykład 13) Programowanie w C++ 1 / 26

Laboratorium nr 12. Temat: Struktury, klasy. Zakres laboratorium:

PARADYGMATY PROGRAMOWANIA Wykład 4

Podstawy programowania w języku C++ Zadania

Szablony klas, zastosowanie szablonów w programach

Programowanie w C++ Wykład 11. Katarzyna Grzelak. 13 maja K.Grzelak (Wykład 11) Programowanie w C++ 1 / 30

Programowanie Obiektowo Zorientowane w języku c++ Konstruktory

Programowanie w C++ Wykład 12. Katarzyna Grzelak. 28 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 27

Programowanie w C++ Wykład 14. Katarzyna Grzelak. 3 czerwca K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Programowanie obiektowe w C++ Wykład 12

Materiały do zajęć VII

Programowanie obiektowe w języku C++ dr inż. Jarosław Forenc

PROGRAMOWANIE OBIEKTOWE W C++ cz. 2. Dziedziczenie, operacje wej cia-wyj cia, przeładowanie operatorów.

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Zaawansowane programowanie w języku C++ Klasy w C++

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Język C++ Różnice między C a C++

Operator przypisania. Jest czym innym niż konstruktor kopiujący!

Nowe słowa kluczowe. Komentarze. Wskaźniki typu void. class, delete, new, friend,... /* Komentarz w C i C++ */ // Komentarz w C++ (do końca wiersza)

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) { zdefiniuje. Integer::operator=(ri);

Definiowanie własnych klas

Programowanie w C++ Wykład 12. Katarzyna Grzelak. 20 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 32

Wstęp do programowania obiektowego. Wykład 2

Programowanie 2. Język C++. Wykład 3.

EGZAMIN PROGRAMOWANIE II (10 czerwca 2010) pytania i odpowiedzi

Programowanie obiektowe, wykład nr 7. Przegląd typów strukturalnych - klasy i obiekty - c.d.

Różne właściwości. Różne właściwości. Różne właściwości. C++ - klasy. C++ - klasy C++ - KLASY

C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie C++ - DZIEDZICZENIE.

Programowanie strukturalne i obiektowe. Funkcje

Typy metod: konstruktory, destruktory, selektory, zapytania, iteratory.

Podstawy Programowania Obiektowego

Szablony funkcji i klas (templates)

PROE wykład 3 klasa string, przeciążanie funkcji, operatory. dr inż. Jacek Naruniec

Wyliczanie wyrażenia obiekty tymczasowe

Języki i metody programowania Java. Wykład 2 (część 2)

Programowanie obiektowe

Zaawansowane programowanie w języku C++ Programowanie obiektowe

Programowanie obiektowe - 1.

Zmienne, stałe i operatory

Programowanie Obiektowe i C++

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Instytut Mechaniki i Inżynierii Obliczeniowej Wydział Mechaniczny Technologiczny Politechnika Śląska

Programowanie obiektowe - Przykładowe zadania egzaminacyjne (2005/2006)

Definicje klas i obiektów. Tomasz Borzyszkowski

Instrukcja do pracowni specjalistycznej z przedmiotu. Obiektowe programowanie aplikacji

Pola i metody statyczne. Klasy zawierające pola i metody statyczne

ISO/ANSI C - funkcje. Funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje

Wprowadzenie w dziedziczenie. Klasa D dziedziczy klasę B: Klasa B klasa bazowa (base class), klasa D klasa pochodna (derived class).

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

Mechanizm dziedziczenia

> C++ dziedziczenie. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki

Informatyka I. Dziedziczenie. Nadpisanie metod. Klasy abstrakcyjne. Wskaźnik this. Metody i pola statyczne. dr inż. Andrzej Czerepicki

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy PRAWA PRZYJACIÓŁ KLASY. Dostęp z zewnątrz: Dostęp z wewnątrz:

dr inż. Jarosław Forenc

Transkrypt:

Katedra Informatyki Stosowanej Politechniki Łódzkiej mgr inż. Tomasz Jaworski Programowanie w języku C++ Al. Politechniki 11, 90-924 Łódź ul. Stefanowskiego 18/22, 90-924 Łódź http://tjaworski.kis.p.lodz.pl e-mail: tjaworski@kis.p.lodz.pl

Programowanie w języku C++ 2 1. Od programowania proceduralnego do obiektowego Konstruując program zawsze napotkamy problem definiowania przedmiotów, których opisem program się ten zajmuje. Przez przedmiot należy tu rozumieć zarówno zjawiska, jak i przedmioty rzeczywiste opisywane przez program oraz struktury danych wykorzystywane do tego opisu. W odniesieniu do sposobu definiowania przedmiotów wykształciły się dwa zasadnicze podejścia: proceduralne: Tworzymy strukturę zawierającą parametry definiujące przedmiot i jego stan, a odseparowane funkcje określają jego właściwości. Rozpatrzmy prosty przykład: w celu zdefiniowania punktu na ekranie wystarczy utworzyć następującą strukturę: struct punkt int x, y; ; Wyświetlenie punktu na ekranie umożliwi następująca funkcja: void Narysuj(struct punkt P) //ciało funkcji obiektowe: Dane definiujące przedmiot i metody określające jego właściwości umieszczamy we wspólnym miejscu klasie. W ten sposób następuje integracja danych i metod uprawnionych do ich wykorzystania. Rozpatrzmy ten sam problem, co w przypadku podejścia proceduralnego. class PUNKT int x, y; void Narysuj(void); ; Zdefiniowana powyżej klasa PUNKT zawiera zarówno dane definiujące punkt na ekranie, jak I funkcję pozwalającą na jego wyświetlenie. Definicja przedmiotu i jego właściwości znalazła się w ten sposób w jednym miejscu. Programowanie obiektowe umożliwia: tworzenie programowych modeli przedmiotów poprzez łączenie danych i metod uprawnionych do ich wykorzystania, wspólny opis całych klas przedmiotów, zjawisk i problemów.

Programowanie w języku C++ 3 2. Definiowanie przedmiotów klasy i obiekty Podstawowym pojęciem języka C++ jest klasa. Dla jej opisu konieczne są dwa zasadnicze elementy: dane charakteryzujące przedmiot, funkcje określające jego właściwości. Jak łatwo się domyśleć elementy te muszą znaleźć się w definicji klasy. Definicja klasy rozpoczyna się od tak zwanego słowa kluczowego klasy, którym może być jedno ze słów class, struct, union. Najczęściej wykorzystywane jest słowo kluczowe class. W ciele definicji klasy mogą znaleźć się: deklaracje danych składowych deklaracje i definicje funkcji składowych Wymienione powyżej elementy rozmieszcza się wekcjach definicji klasy, co ilustruje poniższy schemat: class Klasa protected: private:... //funkcje i dane składowe publiczne... //funkcje i dane składowe zabezpieczone... //funkce i dane składowe prywatne ; Specyfikatory atrybutów dostępu mogą być używane wielokrotnie w obrębie definicji klasy. Umieszczając poszczególne elementy definicji klasy w sekcjach określamy, które funkcje programu mają prawo się do nich odwołać. Reguły dostępności mają się następująco: Sekcja prywatna (private) Składowe prywatne widoczne są tylko w obrębie funkcji składowych danej klasy. Jeśli klasa jest definiowana ze słowem kluczowym class, składowe są domyślnie prywatne. Dane składowe definiujemy jako prywatne zwykle w jednej z następujących sytuacji: zmiana wartości składowej przez niepowołaną do tego funkcję zewnętrzną jest ryzykowna lub zmianie tej powinno towarzyszyć wykonanie ściśle określonych czynności. W takiej sytuacji powinna istnieć specjalna funkcja umożliwiająca takie przypisanie, realizująca jednocześnie te operacje, składowa jest przeznaczona tylko do wewnętrznego wykorzystania przez funkcje składowe klasy. Funkcje definiujemy jako prywatne, gdy: ich wywołanie przez funkcje zewnętrzne jest niewskazane, gdy realizują pewien fragment algorytmu i ich wywołanie z zewnątrz nie ma sensu. Sekcja zabezpieczona (protected) Składowe zabezpieczone są widoczne tylko w obrębie funkcji składowych danej klasy i klas wyprowadzonych. Składowe definiujemy jako zabezpieczone, gdy ich użycie nie jest obarczone tak silnymi restrykcjami, jak ma to miejsce w przypadku składowych prywatnych. Funkcje określamy jako zabezpieczone, jeśli dostęp do nich z zewnątrz nie jest wymagany, zaś konieczny jest dostęp do analogicznych funkcji składowych odziedziczonych po przodkach. Sekcja publiczna (public)

Programowanie w języku C++ 4 Składowe publiczne widoczne są w obszarze całego pliku. Publiczne funkcje składowe służą zwykle do sterowania, zmiany parametrów i komunikacji z obiektem. Dane składowe definiuje się jako publiczne w przypadku prostych klas, gdy zmiana wartości pola nie musi być związana z wykonaniem jakichś dodatkowych czynności.!!! DEFINICJA KLASY POWINNA KOŃCZYĆ SIĘ ŚREDNIKIEM!!! Sposób definiowania funkcji zadeklarowanych, lecz nie zdefiniowanych w ciele klasy rozpatrzymy na przykładzie funkcji Rysuj klasy PUNKT. void PUNKT::Rysuj(void) //ciało funkcji Jako nazwę funkcji podajemy nazwę klasy, po której następuje tzw. kwalifikator zakresu (::), a następnie nazwę definiowanej funkcji składowej. 3. Konstruktory i destruktory Idea i budowa konstruktorów Okazuje się, że oprócz deklarowanych funkcji składowych istnieją jeszcze dwie specjalne funkcji, które są albo definiowane przez programistę, albo generowane przez kompilator (jeśli nie zostały wcześniej zdefiniowane). Są to konstruktory i destruktory. Konstruktor jest specjalną, najczęściej przeciążoną funkcją składową wywoływaną niejawnie zawsze wtedy, gdy zachodzi konieczność utworzenia obiektu danej klasy. Deklarowanie i definiowanie konstruktorów podlega niemal tym samym zasadom, co każda zwyczajna funkcja składowa z tym, że: W deklaracji konstruktora nie wolno określać typu zwracanej wartości. Niedozwolony jest nawet specyfikator void, Konstruktory nie mogą być wywoływane tak jak inne funkcje, gdyż są wywoływane niejawnie w czasie tworzenia obiektu, a wybór odpowiedniego konstruktora jest dokonywany na podstawie typów parametrów przekazanych w czasie tworzenia obiektu, Konstruktory nie są dziedziczone, Identyfikator konstruktora musi być identyczny z identyfikatorem klasy, Nie można pobrać adresu konstruktora, Konstruktor nie może być wirtualny. Dwa typy konstruktorów pełnią szczególną rolę: tzw. konstruktor domyślny, czyli bezparametrowy i konstruktor kopiujący. Jeżeli w klasie nie zdefiniowano żadnego konstruktora, to kompilator utworzy własny konstruktor bezparametrowy i kopiujący. Konstruktor służy przede wszystkim do inicjacji danych składowych obiektu. Inicjacji tej można dokonać w dwojaki sposób: dokonując bezpośrednich przypisań w ciele definicji konstruktora, bezpieczniejsze i zgodniejsze z duchem języka C++ jest jednak posłużenie się tzw. listą inicjacyjną. Elementy listy inicjacyjnej przypominają sposób, w jaki inicjowane są obiekty.

Programowanie w języku C++ 5 Przykład: Definicje konstruktorów class PUNKT private: int x, y; unsigned kolor; ciele funkcji PUNKT(void) x=0; y=0; kolor=0; //bezpośrednie przypisania w PUNKT(int _x, int _y, unsigned _kolor = 0); PUNKT(unsigned _kolor); void UstalWsp(int _x, int _y); void UstalKol(unsigned _kolor); void Rysuj(void); ; PUNKT::PUNKT(int _x, int _y, unsigned _kolor): x(_x), y(_y), kolor(_kolor) //lista inicjacyjna PINKT::PUNKT(unsigned _kolor): x(0), y(0), kolor(_kolor) Definicję klasy PUNKT uzupełniono o następujące konstruktory: PUNKT(void); konstruktor domyślny, bezparametrowy, PUNKT(int _x, int _y, unsigned _kolor=0); - konstruktor o trzech parametrach całkowitych, z możliwością przyjęcia domyślnej wartości (zero) ostatniego, PUNKT(unsigned _kolor); - konstruktor z jednym parametrem całkowitym oznaczającym kolor punktu. Konstruktor, zgodnie z nazwą, jest wywoływany podczas tworzenia obiektu danej klasy. Definicja obiektu klasy zawierającej konstruktory może być połączona z jego inicjacją. PUNKT P1, //konstruktor bezparametrowy P2(1, 1), //konstruktor trójparametrowy, trzeci parametr domyślny P3(10, 10, 5), //konstruktor trójparametrowy P4(1), tab[10]; //konstruktor jednoparametrowy //konstruktor bezparametrowy (10x) Jeżeli klasa zawiera jakikolwiek konstruktor zdefiniowany przez programistę, wówczas kompilator nie wygeneruje automatycznie nawet konstruktora domyślnego. Dobrą zasadą zatem jest, że gdy klasa zawiera jakiś konstruktor, należy również zdefiniować ten bezparametrowy. Należy unikać niejednoznaczności, np.:

Programowanie w języku C++ 6 class X X(void); X(int j=2); ; X obj; Jeśli spróbujemy utworzyć obiekt obj klasy X w powyższy sposób, kompilator nie będzie wiedział, który z konstruktorów klasy X ma zostać użyty. Konstruktory kopiujące. Powielanie obiektów Konstruktorem kopiującym klasy X nazywamy konstruktor o jednym parametrze typu referencja klasy X np.: X(const &X); X(const &X, int I = 0); Konstruktor kopiujący jest wywoływany zawsze, gdy zachodzi konieczność skopiowania obiektu danej klasy do innego obiektu tejże klasy choćby podczas inicjacji obiektu innym obiektem, np.: X x = y; Jeśli konstruktor kopiujący nie został zdefiniowany jawnie, kompilator wygeneruje własny. Konstruktor kopiujący definiujemy samodzielnie wówczas, gdy podczas kopiowania obiektów zachodzi konieczność wykonania jakiejś dodatkowej operacji, np. skopiowania związanych z danym obiektem dynamicznych struktur danych. W tym przypadku brak kopiowania danych mogło by spowodować, że dynamiczne obiekty, o których mowa, operowały by na tym samym obszarze pamięci, co nie zawsze jest wymagane. Destruktory Zawsze przed usunięciem obiektu z pamięci wywoływana jest niejawnie specjalna funkcja składowa zwana destruktorem. Jeśli nie została ona zadeklarowana jawnie w obrębie definicji klasy, kompilator wygeneruje własny destruktor. Destruktor jest funkcją o następujących własnościach: nazwą destruktora jest nazwa klasy poprzedzona znakiem tyldy (~), nie wolno określać typu zwracanego przez destruktor, nie jest dozwolony nawet specyfikator void, destruktor może być wywoływany przy użyciu pełnej kwalifikowanej jego nazwy. W celu wywołania destruktora klasy X należy użyć formuły: X::~X(); Destruktor służy do wykonania niezbędnych operacji przed usunięciem obiektu z pamięci. Operacje te mogą być różnorodne: usunięcie z ekranu figury, zwolnienie pamięci dla dynamicznych struktur danych itp.

Programowanie w języku C++ 7 4. Zmienna this Weźmy pod uwagę definicję klasy PUNKT (nieco uproszczoną): class PUNKT int x, y; void UstalWsp(int i, int j) x = I; y = j; P, Q; oraz obiekty P i Q. Zwróćmy uwagę, że wywołania P.UstalWsp(1, 10); Q.UstalWsp(2, 13); nadają wartości składowym odpowiednio obiektom P i Q. Jak widać ta sama funkcja nadaje wartości składowym różnych obiektów. Rodzi się więc pytanie, w jaki sposób odwołania do składowych są wiązane z konkretnymi obiektami. Okazuje się, że wszystkie niestatyczne funkcje składowe otrzymują niejawny parametr this, który wskazuje obiekt, na rzecz którego zostały wywołane. W zwiąsku z tym ciało funkcji UstalWsp w zasadzie wygląda nastepujaco: void PUNKT::UstalWsp(int i, int j) this->x = i; this->y = j; Normalnie operacja this-> jest wykonywana niejawnie. Wskaźnik this ma różne zastosowania. Można go wykorzystywać do zwracania referencji obiektu, dla którego została wywołana dana funkcja składowa, np.: class PUNKT PUNKT& UstalWsp(int i, int j); ; PUNKT& PUNKT::UstalWsp(int i, int j) x = i; y = j; return *this; //zwróć referencję do danego obiektu

Programowanie w języku C++ 8 5. Funkcje i klasy zaprzyjaźnione W niektórych sytuacjach może zachodzić konieczność postępowania niezgodnego z regułami określonymi atrybutami dostępu lub postępowanie takie może znacznie uprościć zapis algorytmu, powodując wygenerowanie bardziej efektywnego kodu wynikowego. Aby zezwolić funkcji zdefiniowanej poza klasą na dostęp do jej składowych prywatnych i zabezpieczonych, trzeba określić relacją przyjaźni między funkcją a tą klasą. Funkcja zaprzyjaźniona (ang. friend) z klasą, mimo że nie jest składową tej klasy, posiada pełne prawa dostępu do wszystkich składowych tej klasy. Relację przyjaźni między funkcją a klasą ustanawia się poprzez umieszczenie deklaracji tej funkcji poprzedzonej słowem kluczowym friend w ciele definicji klasy. class STRING private: char *Str; friend void Drukuj(STRING &); //definicje konstruktorów i destruktora ; void Drukuj(STRING &S) cout << \n << S.Str; main() STRING Imie( Radosław ); Drukuj(Imie); return 0; Dzięki ustaleniu relacji przyjaźni pomiędzy klasą STRING a funkcją Drukuj dozwolony jest w jej ciele dostęp do składowych prywatnych tej klasy. Relację przyjaźni można ustalić również pomiędzy dwiema klasami. Wszystkie funkcje składowe klasy zaprzyjaźnionej z daną mają prawo dostępu do wszystkich komponentów tej klasy, z którą są zaprzyjaźnione. Należy pamiętać, że relacja przyjaźni nie ma odwrotności.

Programowanie w języku C++ 9 class STRING private: char *Str; //definicje konstruktorów i destruktora friend class STR_STREAM; ; class STR_STREAM void Out(STRING &S) cout << \n << S.Str; ; main() STRING S( Ala ma kota ); STR_STREAM Str; Str.out(S); return 0; Deklaracje klas i funkcji zaprzyjaźnionych mogą znaleźć się w dowolnej sekcji definicji klasy nie ma to żadnego wpływu na relację przyjaźni.

Programowanie w języku C++ 10 6. Funkcje operatorowe Język C++ oprócz możliwości tworzenia różnych obiektów pozwala na definiowanie operatorów wykonujących działania na tych obiektach (klasach). Dzięki temu dodawanie wektorów czy łączenie łańcuchów znakowych może zyskać naturalny wygląd (np. jak każda inna operacja matematyczna). Załóżmy, że obiekty klasy WEKTOR reprezentują wektory na płaszczyźnie. Przedstawiona poniżej funkcja main wykonuje działania na obiektach tej klasy. liczbę int main(void) WEKTOR U(1,5), V(2,3), X(-2,1), Z(10,-3); X = U + V; Z = X 5 * V; return 0; //dodawanie wektorów //odejmowanie wektorów i mnożenie wektora przez Normalnie próba wykonania takich operacji na obiektach zakończyła by się komunikatem o błędzie. Aby tego uniknąć, należy zdefiniować takie operatory. Operatory standardowe i przeciążone Język C++ zawiera pewien, dość obszerny zasób operatorów umożliwiających wykonanie operacji na danych typów całkowitych, rzeczywistych oraz operatory indeksowania, wywołania funkcji, dostępu do składowych oraz dynamicznego przydziału pamięci i in. Większość wymienionych operatorów może zostać zdefiniowana dla operandów innych typów. Operację taką nazywamy przeciążaniem operatorów, podobnie jak zdefiniowanie funkcji o tej samym identyfikatorze, ale innych parametrach wejściowych. Spośród całego zbioru operatorów tylko cztery, podobnie jak symbole preprocesora (#, ##), nie podlegają przeciążaniu:..* ::?: Przeciążanie operatorów polega na zdefiniowaniu tzw. funkcji operatorowej. Identyfikatorem funkcji operatorowej jest zawsze słowo kluczowe operator, bezpośrednio po którym wymieniony jest symbol operatora, np.: operator+, operator-, operator<< Funkcja operatora może być: - niestatyczną funkcją składową klasy, na obiektach których działa operator, - funkcją nie będącą składową klasy najczęściej zaprzyjaźnioną, - statyczną funkcją składową klasy. O tym, z którym z wymienionych powyżej przypadków mamy do czynienia, decyduje rodzaj przeciążanego operatora. Operatory jednoargumentowe Operator jednoargumentowy (binarny) można zdefiniować jako: - niestatyczną, bezparametrową funkcję składową klasy, - funkcję o jednym argumencie, nie będącą składową klasy. Stąd wynika, że poniższe wywołanie operatora jednoargumentowego ++: ++X; lub X++;

Programowanie w języku C++ 11 może być traktowane jako: X.operator++() lub operator++(x);, gdzie X to klasa, której funkcją składową jest operator++ lub na której on działa. Jak widać istnieje możliwość zdefiniowania rodzaju operatora jako przed- lub przyrostkowy. Operator przedrostkowy definiujemy tak, jak to przedstawiono dotychczas, przyrostkowy zaś, deklarując go, jako niestatyczną funkcję składową o jednym parametrze o jednym parametrze typu int lub jako funkcję o jednym parametrze danej klasy i dodatkowym parametrze typu int. Parametr ten stanowi dodatkową informację, pozwalającą kompilatorowi na rozróżnienie wersji przed- i przyrostkowej operatora. Zmianie podlega również fakt, iż w przypadku standardowych przyrostkowych operatorów in- i dekrementacji, kiedy to żądana operacja stosowana była dopiero po obliczeniach, dla operatorów przeciążanych jest ona stosowana natychmiast. Przykład. class INTEGER ; int val; INTEGER(int v=0): val(v) INTEGER &operator++() val++; return *this; //przedrostkowy friend INTEGER &operator++(integer &, int); //przyrostkowy void Out(void) cout << \n << val; INTEGER &operator++(integer &a, int) a.val+=2; return a; main() INTEGER a(1), b(2); ++a; b++; a.out(); b.out(); //użycie operatora przedrostkowego //użycie operatora przyrostkowego Operatory dwuargumentowe Operatory dwuargumentowe należą do najczęściej przeciążanych i można je definiować jako: - niestatyczną funkcję składową wówczas działanie X @ Y, gdzie @ - operator dwuargumentowy traktujemy jako: X.operator@(Y), - dwuparametrową funkcję nie będącą składową klasy, na której operacje będą wykonywane działanie X @ Y interpretujemy wówczas jako operator@(x, Y).

Programowanie w języku C++ 12 Obie metody definiowania operatorów dwuargumentowych są tożsamościowe pod warunkiem odpowiedniego ich użycia, co pokazano w poniższym przykładzie. Przykład. class WEKTOR WEKTOR(void): X(0), Y(0) ; WEKTOR(double X, double Y): X(_X), Y(_Y) WEKTOR operator+(wektor&); friend WEKTOR operator-(wektor&, WEKTOR&); friend WEKTOR operator*(double, WEKTOR&); friend ostream &operator<<(ostream&, WEKTOR&); private: double X, Y; ; WEKTOR WEKTOR::operator+(WEKTOR &U) return WEKTOR(this->X + U.X, this->y + U.Y); WEKTOR operator-(wektor &U, WEKTOR &V) return WEKTOR(U.X + V.X, U.Y + V.Y); WEKTOR operator*(double k, WEKTOR &U) return WEKTOR(k * U.X, k * U.Y); ostream &operator<<(ostream &St, WEKTOR &U) St << [ << U.X <<, << U.Y << ] ; return St; main() WEKTOR A(1, 1), B(5, 5), C(-3, 3);

Programowanie w języku C++ 13 return 0; cout << \n << A + B << \n << A B << \n << 2*C + A; W powyższym przykładzie zdefiniowano klasę WEKTOR, reprezentującą wektor o współrzędnych rzeczywistych (double), a następnie zdefiniowano operatory dwuargumentowe umożliwiające dodawanie, odejmowanie oraz mnożenie wektora przez liczbę. Operator dodawania + zdefiniowano jako niestatyczną funkcję składową, zaś operatory odejmowania i mnożenia jako funkcje zaprzyjaźnione z klasą WEKTOR. Przedstawiony sposób definiowania operatorów dwuargumentowych może być traktowany jako wzorzec postępowania przy takiej okazji. Zdefiniowanie operatora << umożliwia zapis wektora w strumieniu wyjściowym (tu ekran). W wyniku wykonania programu zostaną wyprowadzone następujące napisy: [6, 6] [-4 4] [-5, 7] Istnieje możliwość definiowania operatorów dwuargumentowych na dwa sposoby tak jak to przedstawiono powyżej. Wszelkie niejednoznaczności są rozstrzygane przez standardowe dopasowanie argumentów. Operatory dwuargumentowe zdefiniowane jako niestatyczne funkcje składowe klasy podlegają dziedziczeniu przy wyprowadzaniu klas potomnych z danej. Operatory przypisania Każdy z operatorów przypisania: = *= /= %= += -= <<= >>= &= ^= = może zostać zdefiniowany wyłącznie jako niestatyczna funkcja składowa. Operatory przypisania nie są dziedziczone przez klasy wyprowadzone z tej, dla której zostały zdefiniowane. W poniższej definicji klasy wykorzystano funkcje składowe z przykładu poprzedniego. Dodano definicję operatorów przypisania: +=, -=, *=; class WEKTOR WEKTOR(void): X(0), Y(0) ; WEKTOR(double X, double Y): X(_X), Y(_Y) WEKTOR operator+(wektor&); friend WEKTOR operator-(wektor&, WEKTOR&); friend WEKTOR operator*(double, WEKTOR&); friend ostream &operator<<(ostream&, WEKTOR&); WEKTOR &operator+=(wektor&); WEKTOR &operator-=(wektor&); WEKTOR &operator*=(double); private: double X, Y; ;

Programowanie w języku C++ 14 WEKTOR &WEKTOR::operator+=(WEKTOR &U) this->x += U.X; this->y += U.Y; return *this; WEKTOR &WEKTOR::operator-=(WEKTOR &U) this->x -= U.X; this->y -= U.Y; return *this; WEKTOR &WEKTOR::operator*=(double s) this->x *= s; this->y *= s; return *this; main() C += A + B; WEKTOR A(10, 10), B(-5, 4), C(0, 0); cout << C << \n ; cout << C << \n ; C *= -2; cout << C << \n ; C -= A; cout << C << \n ; return 0; W efekcie wykonania programu zostaną wyprowadzona następujące rezultaty: [0, 0] [5, 14] [-10, -28] [-20, -38]