Více o konstruktorech a destruktorech



Podobné dokumenty
Mělká a hluboká kopie

Konstruktory a destruktory

Programování v C++ 3, 3. cvičení

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Programování v C++ 2, 4. cvičení

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

PB161 Programování v jazyce C++ Přednáška 4

Pokročilé programování v jazyce C pro chemiky (C3220) Třídy v C++

PB161 Programování v jazyce C++ Přednáška 4

přetížení operátorů (o)

C++ přetěžování funkcí a operátorů. Jan Hnilica Počítačové modelování 19

Chování konstruktorů a destruktorů při dědění

konstruktory a destruktory (o)

Programování II. Návrh programu I 2018/19

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Programování v C++ 1, 5. cvičení

Dynamicky vázané metody. Pozdní vazba, virtuální metody

Struktura programu v době běhu

Programování v C++ VI

Objektov orientované programování. C++ Akademie SH. 7. Objektov orientované programování. Michal Kvasni ka. Za áte níci C++ 2.

Programování v jazyce C a C++

Generické programování

Jazyk C++ I. Šablony 2

Polymorfismus. Časová náročnost lekce: 3 hodiny Datum ukončení a splnění lekce: 30.března

<surface name="pozadi" file="obrazky/pozadi/pozadi.png"/> ****************************************************************************

ZPRO v "C" Ing. Vít Hanousek. verze 0.3

Správa paměti. Karel Richta a kol. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Karel Richta, 2016

16. února 2015, Brno Připravil: David Procházka. Konstruktory a destruktory

Dědění, polymorfismus

Základy C++ I. Jan Hnilica Počítačové modelování 18

Programování v C++ 1, 6. cvičení

Objektově orientované programování. Úvod

Dědičnost. Časová náročnost lekce: 3 hodiny Datum ukončení a splnění lekce: 23.března

Jazyk C++ 1. Blok 3 Objektové typy jazyka C++ Třída. Studijní cíl. Doba nutná k nastudování. Průvodce studiem

Funkční objekty v C++.

Pokročilé programování v jazyce C pro chemiky (C3220) Statické proměnné a metody, šablony v C++

Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15

Ukazatel (Pointer) jako datový typ - proměnné jsou umístěny v paměti na určitém místě (adrese) a zabírají určitý prostor (počet bytů), který je daný

Vector datový kontejner v C++.

Pokročilé programování v jazyce C pro chemiky (C3220) Pokročilá témata jazyka C++

24. listopadu 2013, Brno Připravil: David Procházka

Dynamická identifikace typů v C++.

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

8 Třídy, objekty, metody, předávání argumentů metod

Jazyk C++ I. Polymorfismus

Principy objektově orientovaného programování

Abstraktní třídy, polymorfní struktury

Dynamika objektů. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze

PB přednáška (12. října 2015)

Virtuální metody - polymorfizmus

přetížení operátorů (o)

Programování v C++, 2. cvičení

C++ objektově orientovaná nadstavba programovacího jazyka C

Programování v C++ 1, 1. cvičení

IRAE 07/08 Přednáška č. 2. atr1 atr2. atr1 atr2 -33

PB161 Programování v jazyce C++ Přednáška 9

Programování v jazyce JavaScript

- dělají se také pomocí #define - podobné (použitím) funkcím - předpřipravená jsou např. v ctype.h. - jak na vlastní makro:

7. přednáška - třídy, objekty třídy objekty atributy tříd metody tříd

TŘÍDY POKRAČOVÁNÍ. Události pokračování. Příklad. public delegate void ZmenaSouradnicEventHandler (object sender, EventArgs e);

Úvod do programovacích jazyků (Java)

Jazyk C++ I. Šablony

Jazyk C# a platforma.net

Přetěžování operátorů

PB161 Programování v jazyce C++ Přednáška 8

Pole stručný úvod do začátku, podrobně později - zatím statická pole (ne dynamicky) - číslují se od 0

Programování v C++ 2, 8. cvičení

Střední škola pedagogická, hotelnictví a služeb, Litoměříce, příspěvková organizace

Seminář Java II p.1/43

Správné vytvoření a otevření textového souboru pro čtení a zápis představuje

Pole a kolekce. v C#, Javě a C++

Ukazatele, dynamická alokace

NPRG031 Programování II 1 / :25:46

NMIN201 Objektově orientované programování 1 / :36:09

int ii char [16] double dd název adresa / proměnná N = nevyužito xxx xxx xxx N xxx xxx N xxx N

15. Projekt Kalkulačka

IB111 Programování a algoritmizace. Objektově orientované programování (OOP)

Iterátory v C++. int pole[20]; for (int *temp = pole, temp!= &pole[20]; temp++) { *temp = 0;

Základy objektové orientace I. Únor 2010

Objektové programování

Pokročilé programování v jazyce C pro chemiky (C3220) Dědičnost tříd v C++

Přetěžování operátorů

Syntaxe vyjímek. #include <iostream> #include <string> using namespace std; // Trida vyjimek class Vyjimka { private:

Funkce, intuitivní chápání složitosti

Jazyk C++ II. STL knihovna kontejnery část 1

10. března 2015, Brno Připravil: David Procházka. Programovací jazyk C++

PŘETĚŽOVÁNÍ OPERÁTORŮ

Úvod Třídy Rozhraní Pole Konec. Programování v C# Hodnotové datové typy, řídící struktury. Petr Vaněček 1 / 39

Šablony funkcí a tříd (Templates) Genericita

Úvod do programovacích jazyků (Java)

PROGRAMOVÁNÍ V C++ URČENO PRO VZDĚLÁVÁNÍ V AKREDITOVANÝCH STUDIJNÍCH PROGRAMECH ROSTISLAV FOJTÍK

Práce s polem a pamětí

Ukazka knihy z internetoveho knihkupectvi

SYSTÉMOVÉ PROGRAMOVÁNÍ Cvičení č.1

Programování v C++ 1, 14. cvičení

PB161 Programování v jazyce C++ Přednáška 5

Úvod do programování - Java. Cvičení č.4

4. Rekurze. BI-EP1 Efektivní programování Martin Kačer

Standardní algoritmy v C++.

Základy programování (IZP)

Transkript:

Více o konstruktorech a destruktorech

Více o konstruktorech a o přiřazení... inicializovat objekt lze i pomocí jiného objektu lze provést přiřazení mezi objekty v původním C nebylo možné provést přiřazení mezi proměnnými typu struktura, bylo nutné provést kopii po položkách v obou případech se provádí bitová kopie všech atributů

#include "TKomplex.h" void main(void) TKomplex c1(3,4); TKomplex c2 = c1; TKomplex c3; zde se provádí bitová kopie objektů, nevolá se konstruktor c1.set_num(-4,5); c3 = c1; zde se provádí bitová kopie objektů

Bitová kopie může někdy způsobovat problémy! uvažujme třídu, pomocí které implementujeme n-rozměrný vektor vektor je představován dynamicky alokovaným polem

class TVektor int velikost; int *vektor; public: TVektor(); TVektor(int vel); ~TVektor(); int vrat_vel(); int pricti(tvektor v); void zmen_velikost(int nova_vel); void nastav_slozku(int hodn, int index); int vrat_slozku(int index); ;

#include "TVektor.h" void main(void) TVektor v1(2), v2(2); v1.nastav_slozku(-4,0); v1.nastav_slozku(2,1); v2.nastav_slozku(1,0); v2.nastav_slozku(2,1); v1.pricti(v2); //ve v1 bude (-3,4) int i; for(i=0;i<v1.vrat_vel();i++) cout << v1.vrat_slozku(i) << endl;

TVektor::TVektor() velikost = 10; vektor = new int[10]; TVektor::TVektor(int vel) velikost = vel; vektor = new int[vel]; TVektor::~TVektor() delete [] vektor; ;

void TVektor::nastav_slozku(int index, int hodn) if (index < velikost && index >= 0) vektor[index] = hodn; void TVektor::vrat_slozku(int index) if (index < velikost && index >= 0) return vektor[index]; else return -1;

int TVektor::vrat_vel() return velikost; int TVektor::pricti(TVektor v) if (velikost==v.velikost) for(int i=0;i<velikost;i++) vektor[i] += v.vektor[i]; return 1; return 0; POZOR! viz dále

void TVektor::zmen_velikost(int nova_vel) if (nova_vel > velikost) int *novy = new int[nova_vel]; memcpy(novy,vektor,sizeof(int)*velikost); delete []vektor; vektor = novy; velikost = nova_vel;

#include "TVektor.h" void main(void) TVektor v1(20); TVektor v2 = v1; TVektor v3(10); v1.nastav_slozku(-4,1); zde se provádí bitová kopie objektů v3 = v1; v1.pricti(v2);

Po vytvoření objektů v1: velikost pole 20 P1: v2: velikost 20 pole v3: velikost 10 P2: pole

Po přiřazení v3 = v1 v1: velikost pole 20 P1: v2: velikost 20 pole v3: velikost 20 P2: pole

ukazatel vektor ukazuje u instancí v1, v2 a v3 na stejné dynamické pole při změně hodnot v2 se mění i v1 u instance v3 jsme ztratili ukazatel na alokované pole P2; paměť již programátor nemůže vrátit operačnímu systému

Mějme dva vektory v1: velikost 20 P1: pole velikost v2: 20 P2: pole

Při volání metod může nastat ještě závažnější problém při volání metody v1.pricti(v2) se na zásobník uloží lokální kopie objektu v2: 20,vektor ukazatel vektor ukazuje na pole P2 při ukončení metody se ruší lokální kopie objektu v2, tedy je nad touto kopií zavolán destruktor protože kopie ukazatele ukazuje na P2, je toto pole P2 dealokováno! paměť pro P2 může být pak přidělena jinému programu a obsah přepsán!

velikost pole v2: 20 P2: velikost pole 20 bitová kopie v2 na zásobníku nad ní se před ukončením metody pricti zavolá destruktor, tj. dealokuje se P2

Řešení předáváme-li objekt jako parametr metodám (obecně procedurám a funkcím), předáme jej odkazem (jako typ reference) nebo pomocí ukazatele: TVektor::pricti(TVektor &v) nebo TVektor::pricti(TVektor *v)

pro inicializaci objektu jiným objektem při vytvoření deklarujeme zvláštní typ konstruktoru, tzv. kopírující konstruktor (copy constructor) kopírující konstruktor má jediný parametr, a to (konstantní) referenci na jiný objekt téže třídy kopírující konstruktor se vyvolá vždy, když vytvořený objekt má být inicializován kopií jiného objektu téže třídy (např. také při předání objektu jako parametru do procedur)

class TVektor int velikost; int *vektor; public: TVektor(const TVektor &v); atd. ; kopírující konstruktor TVektor::TVektor(const TVektor &v) velikost = v.velikost; vektor = new int[v.velikost]; memcpy(vektor,v.vektor,sizeof(int)*velikost);

#include "TVektor.h" void main(void) TVektor v1(20); TVektor v2 = v1; TVektor v3(10); zde se implicitně volá kopírující konstruktor v1.nastav_slozku(-4,1); v3 = v1; zde se nevolá kopírující konstruktor

máme-li deklarován kopírující konstruktor, pak deklarace funkce pricti(tvektor v) nepřináší problémy, protože při inicializaci lokální kopie objektu na zásobníku skutečným parametrem se provádí voláním kopírujícího konstruktoru problém u přiřazení vyřešíme: vytvořením speciální metody prirad a operátor = nebudeme používat přetížením operátoru = vzhledem ke třídě TVektor, což se budeme učit někdy příště

v1.pricti(v2) s kopírujícím konstruktorem v2: velikost pole 20 P2: velikost pole 20 memcpy(vektor,v.vektor,sizeof(int)*velikost); vektor = new int[v.velikost]; lokální kopie v2 na zásobníku se vytvoří pomocí kopírujícího konstruktoru

Úkol Naimplementujte a vyzkoušejte třídu vektor. Doplňte do konstruktorů a destruktorů jednoduché výpisy typu Volání konstruktoru a vyzkoušejte, zejména u funkce pricti, je-li parametrem objekt nebo reference na objekt. Doplňte kopírující konstruktor a opět pomocí výpisu hlášení vyzkoušejte, kdy se volá.

Podobné problémy mohou nastat, vrací-li funkce objekt... #include "TKomplex.h" //funkce vrací objekt TKomplex k_soucet(tkomplex &c1, Tkomplex &c2) TKomplex c; c.set_num(c1.vrat_real()+c2.vrat_real(), c1.vrat_imag()+c2.vrat_imag()); return c;

void main() TKomplex c1(3,4),c2(-1,-1),s; s = k_soucet(c1,c2); printf("vysledek: %f + %fi", s.vrat_real(),s.vrat_imag());

Co se ve funkci k_soucet děje? na zásobník se předají jako parametry odkazy na objekty c1 a c2 po vstupu se na zásobníku vytvoří lokální objekt c (zavolá se implicitní konstruktor) po skončení funkce vrací objekt c, tj. bitovou kopii atributů, nad lokálním objektem c je vyvolán destruktor

bitová kopie lokálního objektu c je po ukončení funkce k_soucet() v hlavním programu uložena v dočasném objektu, který je přiřazen (opět bitovou kopií) do objektu s; nad dočasným objektem je opět volán destruktor zde to nevadí, ale u objektů, kde je např.v konstruktoru alokována dynamická paměť za běhu, jsou problémy zřejmé pomůže kopírující konstruktor

Co z toho vyplývá? Abychom dobře programovali v jazyku C/C++, musíme znát detaily jazyka a vnitřní mechanismy (volání metod, předávání parametrů). Při tvorbě programů musíme mít stále na zřeteli, co se děje uvnitř. Jinak se nám může stát, že program nebude pracovat správně, havaruje apod. a budeme překvapeni jeho chováním. Bez znalosti detailů budeme pracně hledat příčinu.

Řešení 1. kopírující konstruktor + přetížení operátoru "=" 2. funkce vrací místo objektu ukazatel, resp. referenci na objekt nesmí vracet ukazatel na objekt, který je lokální v proceduře, tj. bude zrušen

špatně: TKomplex *funkce() TKomplex c; kód return &c; vracíme ukazatel na objekt, který je lokální ve funkci a po jejím skončení zaniká

správně: TKomplex *funkce() TKomplex *c; c = new TKomplex; kód return c; o uvolnění paměti se musí postarat např. hlavní program

Použití: void main() TKomplex c1(3,4),c2(-1,-1),*s; s = funkce(); delete s;