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

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

C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm POLIMORFIZM

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

Klasa dziedzicząca posiada wszystkie cechy klasy bazowej (plus swoje własne) dodawanie nowego kodu bez edycji (i ewentualnego wprowadzania

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

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

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

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

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

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

Języki programowania C i C++ Wykład: Typy zmiennych c.d. Operatory Funkcje. dr Artur Bartoszewski - Języki C i C++, sem.

Języki i techniki programowania Ćwiczenia 2

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy KONSTRUKTORY

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

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

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

Podstawy programowania. 1. Operacje arytmetyczne Operacja arytmetyczna jest opisywana za pomocą znaku operacji i jednego lub dwóch wyrażeń.

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

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

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

Przeciążanie operatorów

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.

Funkcje przeciążone, konstruktory kopiujące, argumenty domyślne

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

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

Szablony klas, zastosowanie szablonów w programach

TEMAT : KLASY DZIEDZICZENIE

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

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

Język C++ zajęcia nr 2

Wykład 5: Klasy cz. 3

Zmienne, stałe i operatory

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

Przeciążenie operatorów

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

Wykład 4: Klasy i Metody

Dr inż. Grażyna KRUPIŃSKA. D-10 pokój 227 WYKŁAD 7 WSTĘP DO INFORMATYKI

Lab 9 Podstawy Programowania

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

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Programowanie obiektowe. Materiały przygotował: mgr inż. Wojciech Frohmberg

Języki i paradygmaty programowania

Wykład 8: klasy cz. 4

Wstęp do wskaźników w języku ANSI C

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

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

ROZDZIAŁ 2. Operatory

PARADYGMATY PROGRAMOWANIA Wykład 3

W dowolnym momencie można zmienić typ wskaźnika.

Programowanie Obiektowe i C++

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

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Zaawansowane programowanie w języku C++ Przeciążanie operatorów

Programowanie obiektowe i C++ dla matematyków

Materiały do zajęć VII

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

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

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

Tablice (jedno i wielowymiarowe), łańcuchy znaków

Laboratorium nr 10. Temat: Funkcje cz.2.

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

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Wyliczanie wyrażenia obiekty tymczasowe

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. Słownik programisty: Struktury jako typy abstrakcyjne

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

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

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

IX. Wskaźniki.(3 godz.)

Aplikacje w środowisku Java

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

Wykład 2 Składnia języka C# (cz. 1)

2. Tablice. Tablice jednowymiarowe - wektory. Algorytmy i Struktury Danych

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

Część 4 życie programu

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

Odczyt danych z klawiatury Operatory w Javie

Programowanie, część I

Podstawy Programowania Obiektowego

Wstęp do informatyki- wykład 12 Funkcje (przekazywanie parametrów przez wartość i zmienną)

Programowanie i struktury danych. Wykład 4 Dr Piotr Cybula

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

MATERIAŁY DO ZAJĘĆ II

Operacje wykonywane są na operandach (argumentach operatorów). Przy operacji dodawania: argumentami operatora dodawania + są dwa operandy 2 i 5.

> C++ wskaźniki. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki 26 kwietnia 2017

Ok. Rozbijmy to na czynniki pierwsze, pomijając fragmenty, które już znamy:

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania

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

PARADYGMATY PROGRAMOWANIA Wykład 4

Programowanie w języku C++

Programowanie obiektowe i C++ dla matematyków

Rozdział 4 KLASY, OBIEKTY, METODY

utworz tworzącą w pamięci dynamicznej tablicę dwuwymiarową liczb rzeczywistych, a następnie zerującą jej wszystkie elementy,

Podstawy programowania w języku C i C++

Podstawy Programowania Obiektowego

Tablice mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

Instrukcja do ćwiczeń nr 4 typy i rodzaje zmiennych w języku C dla AVR, oraz ich deklarowanie, oraz podstawowe operatory

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

Transkrypt:

WSKAŹNIKI KLASOWE Wskaźniki klasowe Każdy obiekt zajmuje fragment pamięci i wszystkie obiekty tego samego typu zajmują fragmenty pamięci tej samej długości początek miejsca w pamięci zajmowanego przez obiekt jest nazywany wskaźnikiem na ten obiekt wskaźnik przechowuje adres pierwszej komórki pamięci od której zaczyna się fragment pamięci zajęty przez ten obiekt miejsce w pamięci, w którym przechowywane są poszczególne składowe obiektu jest zawsze w tym samym położeniu względem początku obiektu wartość przesunięcia względem początku to adres względny składowej mając adres względny i adres bezwzględny obiektu możemy odwołać się do składowej obiektu za pomocą jej adresu bezwzględnego 207 208 Wskaźniki klasowe do pól Żeby przechować wartość adresu względnego składowej w zmiennej, potrzebujemy mieć dla niej zdefiniowany typ. W C++ kontrola typów jest bardzo restrykcyjna, więc nie może to być jakiś ogólny typ, ale konkretnie przeznaczony do tego jednego typu składowej. Składowa innego typu będzie miała zdefiniowany inny typ dla swojego adresu względnego. Przyjmijmy, że w klasie MojaKlasa są zdefiniowane składowe typu int. Wtedy wskaźnik względny do składowych tego typu będzie miał typ: Wskaźniki klasowe do pól class MojaKlasa int a,b; MojaKlasa(); int fun(int x); } int MojaKlasa::*wska = &MojaKlasa::a; int MojaKlasa::*wskb = &MojaKlasa::b; int MojaKlasa::*wsk; Symbol & nie oznacza tu pobrania bezwzględnego adresu żadnego obiektu, ale oznacza, że wartościami wskaźników klasowych wska i wskb będzie Uwaga: wskaźnikom klasowym nie można przypisać wskazań na składowe statyczne przesunięcie składowej względem dowolnego obiektu klasy MojaKlasa. w tym przypadku stosuje się zwykłe wskazania. 209 210 Wskaźniki klasowe do pól class MojaKlasa int a,b; MojaKlasa(); int fun(int x); } int MojaKlasa::*wska = &MojaKlasa::a; MojaKlasa mk(); MojaKlasa *mkwsk = NULL; // tutaj tworzymy obiekt typu MojaKlasa mk.*wska = 3; mkwsk->*wska = 3; Wskaźniki klasowe do metod class MojaKlasa int a,b; MojaKlasa(); int fun(double x); } int (MojaKlasa::*funwsk)(double); funwsk = &MojaKlasa::fun; // tworzymy wskaźnik // inicjalizujemy wskaźnik MojaKlasa mk(); MojaKlasa *mkwsk = NULL; // tutaj tworzymy obiekt typu MojaKlasa (mk.*funwsk)(3.14); (mkwsk->*funwsk) (3.14); 211 212 1

Operatory są elementami języka C++. Istnieje zasada, że z elementami języka, takimi jak np. słowa kluczowe, nie można dokonywać żadnych zmian, przeciążeń, itp. PRZECIĄŻANIE OPERATORÓW Ale dla operatorów zrobiono wyjątek: operatory można przeciążać. 214 Co to znaczy przeciążyć operator? Przeciążanie operatorów polega na napisaniu nowych funkcji lub metod, które wywołujemy w taki sam sposób jak operatory. Nie da się modyfikować sposobu działania już zdefiniowanych przypadków użycia danego operatora, ale można wprowadza nowe, których do tej pory nie było i których obecność ułatwi pisanie kodu. Nie przeciąża się operatora dodawania dwóch liczb typu double. Można natomiast przeciążyć operator dodawania tak aby można było pisać wyrażenia arytmetyczne, których argumentami są obiekty zdefiniowanego przez nas typu. Dlatego.. jedynie wyrażenia obejmujące typy zdefiniowane przez użytkownika mogą zawierać przeciążone operatory. 215 216 Definiując funkcję reprezentującą przeciążony operator, jako jej nazwę piszemy: operator@, gdzie znak @ reprezentuje przeciążony operator (np. +, -, /, *..) Istnieją cztery możliwości: 1. Operator przeciążony może być zdefiniowany jako 1. funkcja globalna, albo 2. metoda należąca do klasy. 2. Operator przeciążony może być 1. jedno-, albo 2. dwuargumentowy. Jeżeli przeciążamy operator, który ma działać jako funkcja globalna, to po słowie operator@ zapisujemy 1. dwa argumenty jeżeli jest to operator dwuargumentowy, lub 2. jeden jeżeli jednoargumentowy Jeżeli przeciążamy operator, który ma działać jako metoda należąca do klasy, to po słowie operator@ mamy 1. brak argumentów, jeżeli operator jest jednoargumentowy, lub 2. jeden argument jeżeli dwuargumentowy. W tym przypadku obiekt, na rzecz którego będzie wywoływany przeciążony operator staje się argumentem lewostronnym 217 218 2

Przykład: Zdefiniujmy klasę, która ma reprezentować liczbę typu całkowitego (integer). Chcielibyśmy, aby na obiektach tej klasy można było dokonywać operacji arytmetycznych w taki sam sposób, jak na zmiennych typu int. Klasa będzie nazywała się Integer Na początek będziemy dla niej potrzebowali: 1. konstruktora pozwalającego na ustalenie przechowywanej wartości oraz 2. operator dwuargumentowy: +=, przy czym argumentami operatora mają być obiekty typu Integer Integer(int ii): i(ii) Integer& operator+=(const Integer& rv) int get_i() return i; Integer I(1), J(2); I += J; 219 220 Ponieważ operator jest dwuargumentowy, definiujemy jeden argument wywołania Przekazujemy argument przez referencje aby niepotrzebnie nie wymuszać tworzenia kopii Deklarujemy argument jako const aby zagwarantować mu nietykalność Ponieważ operator nie zwraca żadnej wartości, moglibyśmy napisać: void operator+=(const Integer& rv) ale.. Integer(int ii): i(ii) Integer& operator+=(const Integer& rv) int get_i() return i; Integer I(1), J(2); I += J;..w C++ przyjmujemy że wszystkie operacje przypisania oprócz czynności przekopiowania wartości dodatkowo zwracają je jako rezultat swego działania. To umożliwia tworzenie wyrażeń kaskadowych: A+=B+=C+=D; Aby zachować tę właściwość deklarujemy, że operator zwraca referencję do obiektu typu Integer Integer(int ii): i(ii) Integer& operator+=(const Integer& rv) int get_i() return i; Integer I(1), J(2); I += J; 221 222 Operator dodawania Działając na typach wbudowanych, dodawanie polega na utworzeniu zmiennej pomocniczej i zapisaniu do niej wyniku sumowania wartości z lewego i prawego argumentu wyrażenia: int a, b=1, c=2; a = b + c; Operator dodawania const Integer operator+(const Integer& rv) return Integer(i+rv.i); Metoda tworzy zmienną lokalną takiego samego typu, której zadaniem będzie przechować wynik dodawania. Metoda zwraca tę zmienną, która jest następnie kopiowana np. do zmiennej po lewej stronie równości: a = b + c; Po kopiowaniu zmienna lokalna jest usuwana. 223 224 3

const Integer operator+(const Integer& rv) return Integer(i+rv.i); Integer(int ii): i(ii) printf("%i\n",i); Integer& operator+=(const Integer& rv) const Integer operator+(const Integer& rv) return Integer(i+rv.i); int get_i() return i; Integer I(1), J(2), K(3); I += J + K; printf("%i\n",i.get_i()); // co pojawi się w oknie konsoli? Zmienna lokalna zwracana przez metodę jest obiektem tymczasowym: ma za zadanie tylko zwrócić wartość i zniknąć. Nie zwracamy jej przez podanie jej adresu (to byłoby niebezpieczne!), tylko przez wartość Ponadto deklarujemy ją jako const. Ma to chronić przed takimi wybrykami, jak np. wywołanie metody należącej do obiektu zwracanego przez wyrażenie, np. : (a+b).fun() Dzięki uczynieniu wartości zwracanej jako const określa się, że dla tej wartości mogą być wywołane jedynie stałe składowe (również metody) klasy Integer. To zapobiega umieszczeniu w obiekcie nowej, potencjalnie wartościowej informacji 225 226 Czego nie wolno robić? Nie można tworzyć operatorów, które nie posiadają znaczenia w języku C, np. poprzez łączenie już istniejących (nowy operator ** utworzony w ten sposób mógłby oznaczać potęgowanie, ale niestety..) Nie wolno zmieniać kolejności obliczania operatorów Nie wolno zmieniać liczby argumentów Operatory jednoargumentowe minus i negacja: const Integer operator-() return Integer(-i); const Integer operator!() return Integer(!i); Integer I(1), J(2), K(3); I = -J; printf("%i\n",i.get_i()); I =!K; printf("%i\n",i.get_i()); 227 228 Inkrementacja i dekrementacja Jak rozróżnić wywołanie przyrostkowe i przedrostkowe (operator w obydwu przypadkach wygląda tak samo)? Okazuje się, że kompilator już sobie z tym poradził pierwszy w związku z typami wbudowanymi: 1. jeżeli kompilator widzi ++a, generuje wywołanie funkcji operator++(a) 2. jeżeli kompilator widzi a++, generuje wywołanie funkcji operator++(a,int) Kompilator rozróżnia te dwie postacie wywołując dwie funkcje mające różne sygnatury. Kompilator sam przekazuje sztuczną, stałą wartość argumentu typu int const Integer& operator++() i++; const Integer operator++(int) Integer wart_przed(i); i++; return wart_przed; friend const Integer& operator--(integer &a); friend const Integer operator--(integer &a, int); const Integer& operator--(integer &a) a.i--; return a; const Integer operator--(integer &a, int) Integer wart_przed(a.i); a.i--; return wart_przed; 229 230 4

const Integer operator*( Integer &a) return Integer(i *a.i); friend const Integer operator/(integer &arg_lewy, Integer &arg_prawy); const Integer operator/(integer &arg_lewy, Integer &arg_prawy) if (arg_prawy.i == 0) return Integer(INT_MAX); else return Integer(arg_lewy.i/arg_prawy.i); Argumenty: 1. jeżeli zamierzamy tylko odczytywać zwracaną wartość, argument powinien zostać przekazany jako referencja do stałej (const). 2. Jedynie w przypadku operatorów zmieniających argument po lewej stronie (połączonych z przypisaniem, jak np. += oraz operator= ) argument po lewej stronie nie może być stałą Zwracane wartości: 1. Typ wartości zwracanej przez operator powinien zależeć od spodziewanego znaczenia operatora 2. Wartości zwracane przez operatory przypisania powinny być referencjami do l-wartości, niebędącymi referencjami do stałych 3. Wynikiem działania operatorów logicznych są przynajmniej liczby całkowite a najlepiej wartości typu bool. Nie należy tego zmieniać 231 232 W przeciążonym operatorze mnożenia można napisać tak: const Integer operator*(integer &a) return Integer(i *a.i); albo tak: const Integer operator*(integer &a) Integer tmp(i * a.i); return tmp; W przeciążonym operatorze mnożenia można napisać tak: return Integer(i * a.i); albo tak: Integer tmp(i * a.i); return tmp; Przypadek pierwszy: utwórz tymczasowy obiekt w miejscu przeznaczonym na wartość zwracaną przez funkcję jedna operacja Przypadek drugi: Czy jest różnica w działaniu? utwórz lokalny obiekt tmp, wywołaj konstruktor kopiujący, żeby skopiować tmp do miejsca znajdującego się na zewnątrz funkcji, przeznaczonego na zwracaną przez nią wartość. wywołaj destruktor tmp usuwając ten obiekt trzy operacje 233 234 Przeciążanie operacji przypisania Gdy używany jest znak = to czasem następuje przypisanie, a czasem wywoływany jest konstruktor kopiujący, np. : 1. Integer a(1); 2. Integer b = a; 3. b = a; W drugiej linijce tworzony jest nowy obiekt oraz inicjalizowany wartością a. Przy tworzeniu wywoływany jest zawsze konstruktor. Kompilator połączy to w całość i wywoła konstruktor kopiujący: b(a) W trzeciej linijce zostanie wywołana metoda Integer::operator= Z reguły przy inicjalizowaniu obiektu za pomocą =, zamiast dwóch operacji: (1) wywołania konstruktora i (2) operacji przypisania, kompilator chce wykonać jedną: poszukuje konstruktora, który przyjmie jako argument to, co znajduje się po prawej stronie operacji przypisania. Dlatego dla jasności lepiej jest unikać wykorzystywania znaku = do inicjalizacji obiektów i zamiast tego zawsze używać wywołania konstruktora 235 236 5

A jeżeli mamy zwykłe przypisanie wartości..? Jeżeli programista nie zdefiniuje operatora przypisania to kompilator dostarczy własny operator przypisania, który skopiuje obiekt pole po polu. Ten operator może generować błędy, ponieważ: nie będzie działał dla pól stałych, nie będzie działał dla referencji, dla wskaźników skopiuje wartość. Własny operator przypisania const Integer operator=(const Integer &rv) i = rv.i; Gdyby wśród składowych klasy były wskaźniki, należałoby rozstrzygnąć, czy je przepisywać, czy kopiować ich zawartość, ewentualnie jeżeli rozmiary struktur nie byłyby zgodne usunąć poprzednie i założyć nowe o nowym rozmiarze. 237 238 6