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

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

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

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

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

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?

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

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

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

Wykład 8: klasy cz. 4

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

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

Szablony klas, zastosowanie szablonów w programach

Lab 9 Podstawy Programowania

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

Wykład 4: Klasy i Metody

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

PARADYGMATY PROGRAMOWANIA Wykład 4

Materiały do zajęć VII

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

Programowanie w języku C++

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

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

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady

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

Wskaźniki. Informatyka

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

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

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

Wskaźniki. Przemysław Gawroński D-10, p marca Wykład 2. (Wykład 2) Wskaźniki 8 marca / 17

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

Programowanie obiektowe i C++ dla matematyków

ZASADY PROGRAMOWANIA KOMPUTERÓW

Dziedziczenie jednobazowe, poliformizm

Rozdział 4 KLASY, OBIEKTY, METODY

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

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

Laboratorium nr 9. Temat: Wskaźniki, referencje, dynamiczny przydział pamięci, tablice dynamiczne. Zakres laboratorium:

Języki i techniki programowania Ćwiczenia 2

Programowanie Obiektowe i C++

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

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

TEMAT : KLASY DZIEDZICZENIE

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

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

Wykład 5: Klasy cz. 3

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

Konstruktor kopiujacy

Co to jest klasa? Z programistycznego punktu widzenia klasa stanowi typ danych, który odwzorowuje wspólne cechy jakiegoś obiektu.

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

PARADYGMATY PROGRAMOWANIA Wykład 2

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

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Programowanie, część I

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).

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

Podstawy programowania. Wykład 6 Złożone typy danych: struktury, unie. Krzysztof Banaś Podstawy programowania 1

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

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

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

DYNAMICZNE PRZYDZIELANIE PAMIECI

Do czego służą klasy?

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

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Język C++ Programowanie obiektowe

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

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

KURS C/C++ WYKŁAD 6. Wskaźniki

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

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

Klasy. dr Anna Łazińska, WMiI UŁ Podstawy języka Java 1 / 13

Podstawy programowania obiektowego

Język C zajęcia nr 11. Funkcje

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

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

Wykład 1: Wskaźniki i zmienne dynamiczne

Podstawy programowania skrót z wykładów:

Zmienne i struktury dynamiczne

Wprowadzenie do programowanie obiektowego w języku C++

Podstawy programowania. Wykład PASCAL. Zmienne wskaźnikowe i dynamiczne. dr Artur Bartoszewski - Podstawy prograowania, sem.

Język C++ zajęcia nr 2

Deklaracja struktury w C++

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

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

Podstawy programowania w języku C++

Programowanie obiektowe

Podstawy Programowania Obiektowego

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

Kurs WWW. Paweł Rajba.

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. Metody stałe w klasie

Wstęp do Programowania 2

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

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

Szablony funkcji i szablony klas

Podstawy programowania komputerów

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

Wykład 9: Polimorfizm i klasy wirtualne

Podstawy programowania w języku C++

KLASY cz.1. Dorota Pylak

Transkrypt:

Inicjalizacja obiektu KONSTRUKTORY Inicjalizacja Przyczyną wielu błędów w programach jest nieprawidłowe zainicjalizowanie zmiennych na początku działania programu. Obiekt zawiera z reguły szereg pól ich wartości powinny zostać określone przed rozpoczęciem używania tego obiektu. Umieszczanie instrukcji incjalizujących pola obiektu przed każdą instrukcją tworzącą nowy obiekt mogłoby gmatwać kod programu i zwiększać znacznie jego rozmiar. Aby ułatwić inicjalizację dano programiście możliwość przypisania dowolnego zbioru instrukcji do czynności tworzenia nowego obiektu. Te instrukcje wykonają się za każdym razem kiedy tworzony jest kolejny obiekt. Mogą one inicjalizować pola obiektu. 83 84 Inicjalizacja zbiór instrukcji, który ma być wykonany przy każdym utworzeniu nowego obiektu jest umieszczany w specjalnej metodzie nazywanej konstruktorem. konstruktor może mieć argumenty wywołania (ale nie musi). konstruktor nie ma nazwy. dla jednej klasy można zadeklarować kilka różnych konstruktorów. Konstruktory jednej klasy muszą się różnić sygnaturą, która w przypadku konstruktora oznacza wyłącznie listę typów argumentów wywołania. Przykład deklaracji: X(); // konstruktor Po czym rozpoznajemy konstruktor? 1. nie ma nazwy zamiast nazwy jest powtórzona nazwa klasy 2. nie może zwracać żadnych wartości dlatego nie deklarujemy żadnego typu przed nazwą klasy Definicja konstruktora: X::X() { i = 0; 85 86 Konstruktor może mieć dowolną liczbę argumentów. Konstruktor bezargumentowy jest specjalnym typem konstruktora. Jest to tzw. konstruktor domyślny. Kiedy deklarujemy klasę i nie deklarujemy w niej żadnego konstruktora, konstruktor domyślny tworzy się automatycznie. Kiedy konstruktor domyślny utworzony jest automatycznie, to nie zawiera żadnego kodu. Mimo to JEST. Dlaczego konstruktor domyślny jest konieczny? Ponieważ w każdym miejscu, gdzie tworzony jest obiekt, kompilator po cichu zawsze dodaje wywołanie konstruktora domyślnego. A jak zrobić, żeby przy definicji obiektu został wywołany inny konstruktor? Przykład deklaracji: X(); // konstruktor domyślny X(int a); // inny konstruktor X a1; // tu zostanie wywołany konstruktor domyślny X a2(1); // a tu zostanie wywołany inny konstruktor O tym, który konstruktor ma być wywołany, decyduje liczba argumentów przy nazwie reprezentującej tworzony obiekt. 87 88 1

Konstruktor domyślny jest tworzony zawsze, jeżeli programista nie utworzył żadnego konstruktora. Jeżeli programista utworzył choć jeden konstruktor w klasie, to nawet jeżeli nie jest to konstruktor domyślny, tj. ma jeden lub więcej argumentów, konstruktor bezargumentowy nie będzie już automatycznie tworzony. Dlatego programista, decydując się na tworzenie konstruktorów w klasie, bierze na siebie obowiązek utworzenia również konstruktora domyślnego. Rozważmy fragment kodu: int fun(int x, int y); int g = fun(a,b); Kompilator przy wywołaniu tworzy kopie zmiennych. Na koniec kopiuje wartość zwracaną przez funkcję do zmiennej po lewej stronie równania. Skąd może wiedzieć w jaki sposób zrobić te kopie tj. przekazać i zwrócić wartości zmiennych? Po prostu wie. Bo mu jego autorzy wpisali to kopiowanie na sztywno dla wszystkich typów wbudowanych. A co ma zrobić kompilator, kiedy taka sama sytuacja dotyczy typów utworzonych przez programistę? 89 90 Kiedy potrzeba przekazać argument przez wartość, kompilator dokonuje bezpośredniego przekopiowania bajtów, aby utworzyć zmienne lokalne wykorzystywane wewnątrz funkcji. W przypadku struktur i klas o bardziej złożonym charakterze, takie przekopiowanie może dać fałszywy rezultat. Kompilator nie musi jednak zawsze kopiować bajtów. Zanim to zrobi, najpierw sprawdza, czy istnieje konstruktor, którego argumentem wywołania jest referencja do obiektu tego samego typu, np.: class MojaKlasa { MojaKlasa(); // konstruktor domyślny MojaKlasa(MojaKlasa& mk); // konstruktor kopiujący class MojaKlasa { char **email; int ile; MojaKlasa(int x); ; MojaKlasa:: MojaKlasa(int x) { email = new char*[ile = x]; for (int i=0;i<ile;i++) email[i] = new char[100]; 91 92 class MojaKlasa { char **email; int ile; MojaKlasa(int x); MojaKlasa(MojaKlasa& mk); // konstruktor kopiujący ; MojaKlasa:: MojaKlasa(int x) { email = new char*[ile = x]; for (int i=0;i<ile;i++) email[i] = new char[100]; MojaKlasa::MojaKlasa(MojaKlasa& mk) { email = mk.email; // czy to jest OK? MojaKlasa::MojaKlasa(MojaKlasa& mk) { email = new char*[mk.ile]; ile = mk.ile; for (int i=0;i<ile;i++) { email[i] = new char[100]; strcpy(email[i],mk.email[i]); 93 94 2

Domyślny konstruktor kopiujący Przy kopiowaniu obiektów ZAWSZE używany jest konstruktor kopiujący. Jeżeli programista nie zadeklarował dla klasy/struktury konstruktora kopiującego, kompilator zrobi go sobie sam! Jak będzie działał? Jeżeli składowe klasy są typu wbudowanego, kompilator w konstruktorze kopiującym umieści kod dokonujący kopiowania bajt po bajcie. Jeżeli składowe reprezentują obiekty, kompilator wywoła rekurencyjnie konstruktory kopiujące tych obiektów składowych (jeżeli obiekty składowe będą zawierały inne obiekty, to ich konstruktory kopiujące również zostaną wywołane). Jeżeli składowe-obiekty nie mają zdefiniowanych konstruktorów kopiujących, kompilator utworzy je wg tej samej reguły. Jest to tzw. incjalizacja za pośrednictwem elementów składowych. Usuwanie obiektu DESTRUKTOR 95 96 Końcowe porządki Inną przyczyną wielu błędów w programach jest brak zwolnienia lub nieprawidłowe zwolnienie zmiennych dynamicznych zaalokowanych na początku lub w trakcie działania programu. Obiekt zawiera z reguły szereg pól, które mogą być wskaźnikami przechowującymi adresy zmiennych dynamicznych; przed usunięciem obiektu zmienne dynamiczne należy zwolnić. Umieszczanie instrukcji zwalniających zmienne dynamiczne w każdym miejscu, gdzie może być usuwany istniejący obiekt, mogłoby gmatwać kod programu i zwiększać znacznie jego rozmiar. Aby ułatwić sprzątanie dano programiście możliwość przypisania dowolnego zbioru instrukcji do czynności usuwania istniejącego obiektu. Te instrukcje wykonają się za każdym razem kiedy usuwany jest obiekt. Przykład deklaracji: int* tab; ~X(); // destruktor Po czym rozpoznajemy destruktor? 1. nie ma nazwy jest tylko powtórzona nazwa klasy poprzedzona tyldą 2. nie może zwracać żadnych wartości dlatego nie deklarujemy żadnego typu przed nazwą klasy Defincja destruktora: X::~X() { if (tab!=null) delete []tab; 97 98 Destruktor jest wywoływany zawsze podczas destrukcji obiektu przez system (destruktor obiektu nie niszczy, ale jest wykonywany tuż przed zniszczeniem) Obiekty utworzone jako zmienne lokalne są niszczone automatycznie w momencie opuszczenia bloku w którym zostały zadeklarowane przez sterowanie programu Obiekty dynamiczne utworzone poleceniem new nie są niszczone automatycznie muszą być niszczone poleceniem delete Destruktor musi być bezparametrowy, co oznacza, że nie może być przeciążany (nie można tworzyć wiele destruktorów) restrykcyjne reguły zgodności typów TWORZENIE I USUWANIE OBIEKTÓW 99 3

Ogólnie mówiąc, kiedy w C++ tworzony jest obiekt, zawsze zachodzą dwa procesy: 1. przydzielana jest mu pamięć: w obrębie obszaru danych statycznych zanim rozpocznie się praca programu na stosie kiedy zostanie osiągnięty określony punkt realizacji programu (np. nawias klamrowy otwierający) na stercie kiedy wywołane zostanie polecenie utworzenia zmiennej dynamicznej 2. wywoływany jest konstruktor inicjalizujący tę pamięć Funkcje malloc i calloc są bardzo prymitywne. Aby utworzyć na stercie instancję klasy a potem ją usunąć, należałoby napisać coś w tym rodzaju: class Obj { ; int main() { Obj *obj = (Obj*)malloc(sizeof(Obj);// alokacja pamięci if (obj==0) { perror( nie udało się zaalokować pamięci ); exit(exit_failure); obj->initialize(); // zamiast wywołania konstruktora // tu instrukcje naszego programu obj->destroy(); // zamiast wywołania destruktora free(obj); // zwalnianie pamięci // TAK NIE NALEŻY TWORZYĆ OBIEKTÓW DYNAMICZNYCH! 101 102 W C++ zapominamy o malloc i calloc. Ponieważ w C++ wszystko ma swój konstruktor, który musi być zawsze wywołany, używanie malloc i calloc naruszałoby tę zasadę, ponieważ one nie dają możliwości wywołania konstruktorów i destruktorów. Rozwiązaniem jest połączenie w jeden operator new wszystkich działań koniecznych do utworzenia obiektu. Podczas generowania obiektu dynamicznego poprzez wyrażenie new przydziela się na stercie niezbędną ilość pamięci i wywołuje dla niej właściwy konstruktor, np. : MojTyp *MTp = new MójTyp(1,2,3); Operator new 1.najpierw alokuje stosowny obszar pamięci. 2.Dopiero kiedy alokowanie zakończy się pomyślnie, przystępuje do wywołania konstruktora. Nie ma potrzeby sprawdzania, czy alokacja się powiodła. A jeżeli się nie powiodła wywoływana jest specjalna funkcja new handler. Jej zadaniem jest zgłoszenie wyjątku (o wyjątkach będzie więcej informacji w dalszej części wykładu) Rezultatem działania new jest: 1. zainicjalizowany obiekt, albo 2. obiekt-wyjątek informujący o problemie. 103 104 Wyrażeniem komplementarnym do new jest delete Wyrażenie delete najpierw wywołuje destruktor, a następnie zwalnia przydzieloną uprzednio pamięć, np. : delete MTp; Operator delete może być wywołany wyłącznie w stosunku do obiektu utworzonego wcześniej za pomocą new Jeżeli wskaźnik usuwany za pomocą delete jest NULL, to nic się nie stanie. Z tego względu niektórzy zalecają przypisanie wskaźnikowi wartości NULL zaraz po usunięciu obiektu, żeby w przypadku próby podjęcia usuwania drugi raz dla tego wskaźnika uniknąć problemów. RESTRYKCYJNA POLITYKA KONTROLI ZGODNOŚCI TYPÓW 105 106 4

C++ - zgodność typów Dlaczego w C++ mamy dużo bardziej restrykcyjną politykę kontroli zgodności typów? W języku C funkcja malloc zwraca wskaźnik typu void* czyli po prostu adres w pamięci. Dlatego można było np. napisać: struct ABC { struct ABC *ptr = malloc( sizeof(abc) ); Akceptowana może być konwersja różnych typów adresowych występujących po lewej i prawej stronie operatora przypisania. W C++ taka konwersja jest niedozwolona. C++ - zgodność typów Kontrola typów - przykład: class Obj { ; Obj *ptr1 = new Obj(); void* ptr2 = ptr1; ptr1 = new Obj(); // tu instrukcje naszego programu delete ptr1; delete ptr2; Problem: skąd operator delete ma wiedzieć jaki destruktor ma wywołać dla obiektu wskazywanego przez ptr2? 107 108 C++ - zgodność typów Kontrola typów - przykład: Ponieważ typ void* nie wskazuje na żaden konkretny obiekt, operator delete zwolni tylko pamięć, a żadnego konkretnego destruktora nie będzie próbował wywołać. Ewentualna konwersja do typu void* nie budzi zastrzeżeń kompilator zakłada, że programista, gubiąc informację o typie obiektu, wie co robi: Obj *ptr1 = new Obj(); void* ptr2 = ptr1; Ale próba konwersji w druga stronę jest już traktowana w C++ jako błąd nie tylko zgubimy wtedy informacje o prawdziwym typie obiektu, ale wprowadzimy fałszywą informację o tym, że jest innego typu: ptr1 = ptr2; INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU 109 110 Inicjalizacja agregatowa zmiennej tablicowej int a[5] = {1,2,3,4,5; Struktury są również agregatami, dlatego: struct X { double f; char c; ; Inicjalizacja agregatowa obiektów jest możliwa tylko kiedy spełnione są łącznie następujące warunki: 1. klasa nie zawiera składowych private ani protected, 2. programista nie zaimplementował w niej żadnych konstruktorów, 3. klasa po niczym nie dziedziczy (nie ma swojej klasy bazowej), 4. klasa nie ma metod polimorficznych. X x1 = {1, 2.2, 'c'; Ale tylko pod pewnymi warunkami.. 111 112 5

Tablice struktur struct X { double f; char c; ; X x2[3] = {{1, 2.2, 'c', {2, 1.1, 'b'; Trzeci element tablicy zostanie zainicjowany wartością zerową dla każdego z jego pól 113 Przykłady inicjalizacji agregatowej: struct S1 { int x; struct F1 { int j; int a[3]; b; ; union U1 { int a; const char* b; ; S1 sa = { 1,{2,3,{4,5,6; // OK S1 sb = { 1,2,3,4,5,6; // OK char cr[3] = {'a'; // {'a', '\0', '\0' int ar2d1[2][2] = {{1,2,{3,4; //{1, 2 //{3, 4 int ar2d2[2][2] = {1,2,3,4; //{1, 2 //{3, 4 int ar2d3[2][2] = {{1,{2; //{1, 0 //{2, 0 U1 u1 = {1; // OK 114 Tablice obiektów class Y { double f; char c; Y(int ai, double af, char ac) { /* inicjalizacja */ ; ; Y y3[3]={y(1,2.2,'c'), Y(2, 1.1, 'b'), Y(3, 3.3, 'a'); Jeżeli zdefiniowany jest jawnie konstruktor, to niezależnie czy jest to struktura czy klasa i czy składowe są publiczne czy prywatne inicjalizacja musi odbywać się za pośrednictwem konstruktora Konstruktory typów wbudowanych Typy wbudowane (np. double, int) różnią się od typów definiowanych przez użytkownika, ponieważ nie mają konstruktorów, a więc zmienne musza być inicjalizowane za pomocą operacji przypisania Tak nie jest wygodnie. Dlatego w obecnych implementacjach C++ można już pisać: int a(8); albo (do wyboru): int a = 8; Jeżeli zmienna jest typu wbudowanego, lepiej pisać po staremu 115 116 Kiedy mogą przydać się konstruktory klas wbudowanych? Np. w liście inicjalizatorów konstruktora X(int a): i(a) { ; Wywołania konstruktorów umieszczone po dwukropku za nagłówkiem metody a przed otwierającym nawiasem klamrowym reprezentują listę inicjalizatorów Po co komu taka konstrukcja? Wewnątrz klasy można zadeklarować pole będące stałą, np.: F(int r); void fun(); Takie stałe reprezentują wartości, które są jednokrotnie inicjalizowane i nie mogą już być później zmieniane przez cały czas życia obiektu, ALE: ICH WARTOŚĆ NIE MUSI BYĆ IDENTYCZNA WE WSZYSTKICH OBIEKTACH. To znaczy, że musi być inicjalizowana indywidualnie dla każdego nowego obiektu. Ale jak, skoro nie wolno pisać instrukcji zmieniających wartość stałych? 117 118 6

Rozwiązaniem jest napisanie instrukcji inicjalizującej w miejscu znajdującym się poza kodem wszelkich metod i konstruktorów. Takim miejscem jest lista inicjalizatorów konstruktora: F(int r): rozmiar = r {; F(int r): rozmiar(r) {; void fun(); F a(1), b(2), c(3); // tak mi nie wolno! // tak jest OK. // deklaracja trzech obiektów Inicjalizacja składowych zadeklarowanych na podstawie innych klas Definiując klasę, możemy deklarować jej składowe zarówno na podstawie typów wbudowanych jak i klas class X; class Y { int a,b; // składowe typu wbudowanego int X c; // składowa typu takiego jak klasa Y(); // konstruktor domyślny ; Inicjalizacja dla składowych typów wbudowanych (a i b) polega po prostu na utworzeniu zmiennej, czyli przydzieleniu pamięci. A co ze składowymi zadeklarowanymi na podstawie klas? 119 120 Składowe zdefiniowane na podstawie klas mają również przydzielaną pamięć, ale potem następuje jeszcze wywoływanie konstruktora domyślnego.. Koniecznie domyślnego? Składowe zdefiniowane na podstawie klas mają również przydzielaną pamięć, ale potem następuje jeszcze wywoływanie konstruktora domyślnego.... chyba, że programista dla tych składowych sam wskaże, który konstruktor ma być uruchomiony umieszczając jego wywołanie w liście inicjalizatorów konstruktora: X(); X(double z); class Y { int a,b; // składowe typu wbudowanego int X c; // składowa typu abstrakcyjnego Y(): c(0) { a= 0; b = 0; ; 121 122 Pola statyczne w klasach: Plik h: static int MAX_ROZMIAR; F(int r): rozmiar(r) {; void fun() {; ; Plik cpp: int F::MAX_ROZMIAR = 100; Pole statyczne deklaruje się za pomocą słowa static Pola statyczne stałe, o wartościach określonych podczas kompilacji, w klasach: static const int MAX_ROZMIAR = 100; F(int r): rozmiar(r) {; void fun() {; ; Pole statyczne stałe deklaruje się za pomocą słowa static const Pole statyczne stałe jest wspólne dla wszystkich instancji (!) Pole statyczne stałe inicjalizuje się w miejscu jego deklaracji Pole statyczne jest wspólne dla wszystkich instancji (!) (ale tylko pola typu integral!) 123 124 7

Pola statyczne stałe, o wartościach określonych podczas kompilacji, w klasach: Plik h: static const double 2PI; F(int r): rozmiar(r) {; void fun() {; ; Plik cpp: const double F::2PI = 6.283185335194; Pola referencyjne w klasach: Plik h: class G; G& g; F(int r, G& tempg): rozmiar(r), g(tempg) {; void fun() {; ; Dla pól referencyjnych (tak jak dla zmiennych referencyjnych) można wskazać do jakiej zmiennej/obiektu mają by odniesieniem poprzez inicjalizację ale nie można tego zrobić poprzez operację przypisania. 125 126 Pola referencyjne w klasach: class G; G& g1; G g2; F(G& tempg1, G& tempg2): g1(tempg1) { g2 = tempg2; ; ; Pole g2 najpierw zostanie utworzone i zainicjalizowane konstruktorem domyślnym (ponieważ wszystkie pola niewymienione w liście inicjalizatorów, są incjalizowane konstruktorami domyślnymi) a następnie operator przypisania skopiuje do niego zawartość tempg2. Pola referencyjne w klasach: class G; G& g1; G g2; F(G& tempg1, G& tempg2): g1(tempg1) { g2 = tempg2; ; ; Uwaga: pole g1 musi być inicjalizowane w liście inicjalizatorów, ponieważ nie ma konstruktora domyślnego dla zmiennych referencyjnych. Dlatego pominięcie tej inicjalizacji powoduje błąd kompilacji. 127 128 Pola referencyjne w klasach: class G; G& g1; G g2; F(G& tempg1, G& tempg2): g1(tempg1), g2(tempg2) {; ; Tak jest prościej oraz mamy mniejszy koszt obliczeniowy: pole g2 jest od razu inicjalizowane obiektem tempg2. Komentarz: pola referencyjne w klasach to nie jest dobry pomysł. 129 8