w4 konstruktory(5)

background image

Wykład 4

Konstruktory –cechy

główne

background image

Uwagi ogólne do konstruktorów:

1. Konstruktor

NIE MUSI

wystąpić w opisie klasy, czyli

obiekty nie muszą być wprowadzane konstruktorem.

2. Nazwa konstruktora może być przeładowana

, czyli

stosowana wielokrotnie w opisie klasy z różnymi
listami argumentów. Wtedy kompilator odróżnia
konstruktory po listach argumentów, tak, jak w
przypadku przeładowanych nazw funkcji.
Konstruktorów może więc być wiele.

3. Konstruktor

może być wywoływany ( a nie

deklarowany!!) bez żadnych argumentów

. Jest to tak

zwany konstruktor domniemany. Czasem nazywamy
go domyślnym albo standardowym. Ze względu na
istotę przeładowania nazwy konstruktor domniemany
czyli bezargumentowy może wystąpić tylko raz. Jeśli
nie deklarujemy w klasie żadnego konstruktora, to
kompilator sam ustanawia właśnie konstruktor
domniemany do obsługi obiektów w programie. Każdy
konstruktor z argumentami, którym nadamy wartości
domyślne czyli niedefiniowalne jest także
konstruktorem domniemanym.

background image

Konstruktor jest zwykle deklarowany jako
publiczny, bo przecież wprowadzane nim
obiekty mogą być używane przez klasy
zewnętrzne. Możemy jednak dla
konstruktora przewidzieć ochronę tak, jak
dla klas za pomocą etykiet private lub
protected. Wówczas jednak także
konstruowane obiekty będą dostępne tylko
w obrębie klasy z tym konstruktorem jako
private albo jako protected tylko w
zakresie klas dziedziczących.

Konstruktor może zamiast definiować
obiekty podawać kopie obiektów zawartych
w innej klasie. Wtedy jest to tak zwany

konstruktor kopiujący

.

Konstruktor może dokonywać konwersji
typu obiekty z jednego w drugi. Nazywamy
go wtedy

konstruktorem konwertującym

.

background image

Konstruktor kopiujący

Przyjrzyjmy się wywołaniu konstruktora klasy o nazwie klasa:
 
klasa::klasa(klasa&)
 
Jego argumentem jest referencja do obiektu danej klasy. Taki

konstruktor nie konstruuje obiektu tylko tworzy kopię innego, który
już istnieje wśród obiektów klasy. Pozostałe argumenty konstruktora
są domniemane. Przykładami konstruktora kopiującego mogą być:

X::X(X&)
 
lub
 
X::X(X&, float=3.1415, int=0)
 

background image

Taki konstruktor wprowadza obiekty identyczne z już
istniejącymi, czyli ich kopie.
Taki konstruktor może być wywołany przez program
niejawnie:
1.W sytuacji gdy do funkcji jest

przez wartość

przesyłany

obiekt klasy X. Wówczas tworzona jest kopia tego
obiektu. Jest to tzw. kopiowanie płytkie.
2.W sytuacji kiedy funkcja zwraca przez wartość obiekt
klasy X. Wtedy także tworzona jest kopia obiektu. To
także jest kopiowanie płytkie.
To, że konstruktor kopiujący podaje obiekt kopiowany
przez referencję daje mu możliwość

zmiany zawartości

obiektu klasy!!

(patrz przesyłanie argumentu do funkcji

przez wartość)

background image

Nie można pominąć referencji w konstruktorze
kopiującym, bo gdyby konstruktor X wywoływał obiekty
swojej klasy X przez wartość, czyli wytwarzałby swoją
kopię, to powstaje nie zamknięta pętla tworzenia kopii.
Konstruktor z przyczyn logiki języka otrzymuje więc
warunki do tego aby uszkodzić oryginał!!
Zabezpieczamy się przed taką sytuacją następująco:

X::X(const X&obiekt)

Teraz konstruktor X wie, że obiekt klasy X musi być
wywoływany jako stały. Konstruktor kopiujący jest
domyślnie typu const, czyli nie może zmienić sam siebie.

background image

 
 
1.#include<iostream>
2.#include<string.h>
3.#include<conio.h>
4.class X
5.{public:char*p; X(char*);
6.};
7.class Y
8.{public:
9.char*p; Y(char*);
10.

Y(Y&);

// deklaracja konstruktora kopiajacego obiekty

klasy Y

11.};
12.void main()
13.{
14.X x("xxx"); X j=x; //powolanie do zycia obiektow

x,j klasy X

15.cout<<"\nx="<<x.p<<", j="<<j.p; // wydruk wskaznika czyli

adresu do obiektow x,j

16.strcpy(j.p,"111"); // skopiowanie pod wskaznik obiektu j lancucha

111

17.cout<<"\nx="<<x.p<<", j="<<j.p;

Przykład: konstruktor kopiujący będzie kopiował

wskaźnik do obiektu. (tzw. kopiowanie głębokie)

background image

18.cprintf("\n\rx.p=%p, j.p=%p,x.p,j.p);
19.Y y("yyy"); Y d=y; //

powołanie obiektów klasy Y

20.cout<<"\ny="<<y.p<<", d="<<d.p;
21.strcpy(y.p,"222");
22.cout<<"\ny="<<y.p<<", d="<<d.p;
23.cprintf("\n\ry.p=%p, d.p=%p,y.p,d.p);
24.getch();
25.}
26.X::X(char*s)
27.{p=new char[80]; if(p)strcpy(p,s);
28.}
29.Y::Y(char*s)
30.{p=new char[80]; if(p)strcpy(this->p,s);
31.}
32.Y::Y(Y&y)
33.{p=new char[80]; if(p)strcpy(p,y.p);
34.}

background image

Omówienie przykładu:

5.{public:char*p; X(char*);

Wiersz 5: etykieta public dla klasy X oraz deklaracje
zmiennej własnej p, która jest wskaźnikiem do zmiennej
znakowej

oraz

konstruktor

obiektów

klasy

X

oczekującego

na

liście

parametrów

formalnych

wskaźnika do zmiennej typu string lub charakter. Ciało
tego konstruktora jest podane w wierszu 26-28:

26.X::X(char*s)
27.{p=new char[80]; if(p)strcpy(p,s);
28.}

Wiersz 8-9: analogiczny jak wiersz 5 ale dla klasy Y

8.{public:
9.char*p; Y(char*);

background image

Wiersz 9: konstruktor kopiujący klasy Y. Będzie on
kopiował wskaźnik do zmiennej znakowej, którą
wskaże. Może to być zmienna z innej klasy. Na tym
polega kopiowanie głębokie. W klasie X funkcjonuje
konstruktor kopiujący domyślny tworzony podczas
kompilacji. Daje on kopiowanie płytkie, czyli dotyczące
tylko składników własnej klasy X.

background image

13.{
14.X x("xxx"); X j=x; //powolanie do zycia obiektow

x,j klasy X

Wiersz 13-14: tworzymy obiekt x oraz obiekt j klasy X. Do
obiektu x wpisywany jest element tablicy zarezerwowanej
dla niego przez konstruktor w wierszu 26. Obiekt j jest
inicjalizowany obiektem x. Kopiowanie x do j jest
realizowane przez konstruktor domyślny klasy X.
Przepisuje on wskaźnik do obiektu x do wskaźnika do
obiektu j. Dlatego wskaźnik p w obiekcie j będzie
wskazywał to samo miejsce co wskaźnik p w obiekcie x.
Dlatego wydruk w wierszu 14 powinien podać ten sam
wynik dla każdego z tych obiektów.
Zauważmy, że obiekt j nie ma zarezerwowanej swojej
przestrzeni na tablice znakową, korzysta natomiast ze
zmiennej wskaźnikowej własnej p z klasy X do
podłączenia się do tej samej tablicy co obiekt x. Dlatego
pojawia się szczególny zapis obiektów x oraz j połączony
ze zmienną własną wskaźnikową p.

15.cout<<"\nx="<<x.p<<", j="<<j.p; // wydruk wskaznika czyli
adresu do obiektow x,j
16.strcpy(j.p,"111"); // skopiowanie pod wskaznik obiektu j lancucha
111
17.cout<<"\nx="<<x.p<<", j="<<j.p;

background image

15.cout<<"\nx="<<x.p<<", j="<<j.p; // wydruk wskaznika
czyli adresu do obiektow x,j
16.strcpy(j.p,"111"); // skopiowanie pod wskaznik obiektu j
lancucha 111
17.cout<<"\nx="<<x.p<<", j="<<j.p;

Wiersz 15-17: do tablicy wskazywanej przez
wskaźnik p wpisujemy poprzez kopiowanie
łańcucha wartość ’’111” ale przedtem
sprawdzamy adresy obiektów.
Wiersz 16: wydruk wartości obiektu x oraz j
wskazywanych przez zmienną p
Wiersz 17: wydruk adresów wskazywanych przez
p dla obiektu x oraz j. Te adresy powinny być
jednakowe, czy nie?

background image

18.cprintf("\n\rx.p=%p, j.p=%p,x.p,j.p);
19.Y y("yyy"); Y d=y;

powołanie obiektów klasy Y

20.cout<<"\ny="<<y.p<<", d="<<d.p;
21.strcpy(y.p,"222");
22.cout<<"\ny="<<y.p<<", d="<<d.p;

Wiersze 18-22: powtórzenie takich samych działań ale dla
klasy Y. Wprowadzamy obiekty y oraz d, które grają takie
same role jak poprzednio x oraz j.
Wiersz 21: modyfikujemy łańcuch w obiekcie d.
Wiersz 22: drukujemy wartości obiektów y oraz d nie
spodziewając się ich identyczności jak poprzednio dla x
oraz j. Dlaczego? Dlatego, że konstruktor Y działa przez
referencję, a nie poprzez przypisanie jak konstruktor
kopiujący domyślny. Łańcuch d jest modyfikowany
tylko w miejscu d
. Konstruktor Y zapewnia modyfikację
poprzez referencję.
Wydruk adresów obiektów y oraz d. Powinny być różne!!

background image

26.X::X(char*s)
27.{p=new char[80]; if(p)strcpy(p,s);
28.}

Wiersz 26-28: ciało konstruktora obiektów klasy X.
Operatorem new jest dynamicznie przydzielona
pamięć dla tablicy 80cio znakowej. Kopiowanie
łańcucha z listy parametrów formalnych
konstruktora do tablicy nastąpi tylko wtedy, kiedy
operator new tę pamięć przydzieli.

background image

29.Y::Y(char*s)

30.{p=new char[80]; if(p)strcpy(this->p,s);

31.}

32.Y::Y(Y&y)

33.{p=new char[80]; if(p)strcpy(p,y.p);

34.}

Konstruktory klasy Y. Konstruktor kopiujący powiela
postać konstruktora poza wskazaniem, że dozwala
na kopiowanie obiektów klasy Y do wskaźnika p
spod adresy każdego obiekty klasy Y.

background image

Rezultat na ekranie (przykładowy):
 
x=xxx, j=xxx
x=111, j=111
x.p=2707:0004, j.p=2707:0004
y=yyy, d=yyy
y=yyy, d=222
y.p=270D:0004, d.p=2713:0004


Document Outline


Wyszukiwarka

Podobne podstrony:
w4 konstruktory(1)
w4 konstruktory cd
W4 Proces wytwórczy oprogramowania
W4 2010
Statystyka SUM w4
w4 3
W4 2
W4 1
w4 skrócony
w4 orbitale molekularne hybrydyzacja
Materiały konstrukcyjne
in w4

więcej podobnych podstron