background image

 

 

Klasy obiektów

Wykład 2

background image

 

 

Pojęcie klasy obiektów

Klasa jest nowym typem zmiennej w programie . Definiujemy ją 

jako:

 
class nasza_klasa {
//
//
...
//ciało klasy
};
 
Jeśli chcemy stworzyć konkretny element czyli obiekt tej klasy 

to zapisujemy :

 
nasza_klasa  nasz_obiekt;

 

Wtedy w pamięci operacyjnej 

powstanie 

obiekt klasy 

nasza_klasa, który się nazywa nasz_obiekt

background image

 

 

Kiedy już mamy typ  nasza_klasa, to możemy utworzyć 
obiekt pochodny, na przykład wskaźnik do obiektu z 
naszej_klasy:
 

nasza_klasa *wsk;

(czy mogę określić referencję na nazwę klasy?) 

albo:
 

nasza_klasa &name = obiekcik;

 

Utworzy to wskaźnik do obiektów klasy nasza_klasa albo 
referencje do wybranego obiektu klasy nasza_klasa.
 
Przykładprogram w C++, który przechowuje 
informację o kolorze i wartości punktowej karty do gry. 
Wykorzystuje klasę Karta
. W kodzie ponumerowano 
wiersze do dalszej analizy.

background image

 

 

Kod programu do przykładu

1. #include <iostream>
2. #include <conio.h>
3. #include <string.h>
4. #include <dos.h>
5. class Karta
6. {
7. public:
8. char kol[80];
9. int wym;
10.Karta(char*, int);
11.void Druk();
12.}; 

background image

 

 

void main()
{

Karta k1(“czarna”,5),k2(“czerwona”,8);

// 

powolanie do zycia obiektow k1 oraz k2 klasy Karta

k1.Druk(); 

// 

wykonanie funkcji Druk() na rzecz 

obiektu k1

k2.Druk();

strcpy(k1.kol,”czarno-czerwona”);  //

zmiana zmiennej 

kol na rzecz obiektu k1

k2.wym=28;

//

zmiana zmiennej wym na rzecz 

obiektu k2

cout<<endl;

k1.Druk();
k2.Druk();
getch();

background image

 

 

Karta::Karta(char* s,int w): wym(w)
{
strcpy(kol,s);
}

 

Definicja 
konstrukto
ra

Inicjalizacja 
argumentu 
konstruktora

Definicja 
funkcji

void Karta::Druk()

{

cout<<”\nkolor=”<<kol<<”,wymiar=
”<<wym;

}

background image

 

 

omówienie:

uwagi o strukturze kodu programu: 

•opis klasy Karta znajduje się przed blokiem main() czyli w tej części 
kodu programu, która przeznaczona jest do umieszczania deklaracji, 
definicji  i  inicjalizowania  typów  zmiennych.  To  także  wskazuje,  że 

klasa jest typem zmiennej

•Opis klasy zawsze umieszczamy w nawiasie klamrowym, po którym 
jest średnik, tak, jak w normalnych deklaracjach typów zmiennej.

•Konstruktor obiektu Karta, o ZAWSZE nazwie takiej samej jak klasa 
jest w obszarze opisu klasy  tylko deklarowany i podawana jest lista 
jego argumentów. Nie podajemy typu  pomimo, że jest funkcją.

•Ciało  konstruktora,  który  jest  funkcją,    jest  opisywane 

poza

 

blokiem main()

•W  bloku  definiowania  klasy  deklarowane  są  także  funkcje 
składowe  klasy
,  które  dalej  będą  metodami  obiektów  klasy.  W 
przykładzie jest to funkcja Druk().

•Opis  funkcji  klasy  umieszczamy  po  bloku  main()  tak,  jak  opis 
konstruktora  ale  może  być  podany  także  wewnątrz  bloku  deklaracji 
klasy.

background image

 

 

Opis kodu: 

Wiersze 5-11: początek i koniec opisu klasy Karta zawierający 
deklaracje konstruktora Karta i funkcji Druk() oraz 
wykorzystywanych zmiennych, tablicy char[80] oraz zmiennej 
całkowitej wym

class Karta

{

public:

char kol[80];

int wym;

Karta(char*, int);

void Druk();

}; 

background image

 

 

Wiersze 12-25: blok main(), w którym powołane są dwa obiekty klasy Karta o 
nazwach k1 i k2 w wierszu 14ym. Obiekty mają argumenty takie, jakie 
zadeklarowano w konstruktorze
, czyli zmienna typu char oraz zmienna 
integer. WNIOSEK: deklaracja konstruktora musi zawierać to, co 
potem jest potrzebne w funkcjonowaniu obiektów konstruowanych w 
klasie
. W każdym obiekcie k1 oraz k2 wartości zmiennych deklarowanych są 
zainicjowane poprzez podanie konkretnych wartości. 

void main()

{

Karta k1(“czarna”,5),k2(“czerwona”,8);

k1.Druk();

k2.Druk();

strcpy(k1.kol,”czarno-czerwona”);

k2.wym=28;

cout<<endl;

k1.Druk();

k2.Druk();

getch();} 

background image

 

 

Wiersze 26-33: definicja konstruktora klasy. Najpierw nazwa Karta, a 
potem  operator  ::  czyli  operator  zakresu.  Teraz  już  na  liście 
argumentów formalnych podane są nazwy argumentów s oraz w. Po 
liście  argumentów  formalnych  może  (  ale  nie  musi)  pojawić  się 
dwukropek  i  lista  inicjalizująca  wartości  argumentów,  czyli 
argumenty  początkowe.  Następnie  w  nawiasie  klamrowym,  po 
którym  nie  ma  średnika  umieszczamy  ciało  konstruktora.  W  ciele 
konstruktora,  w  wierszu  27  mamy  kopiowanie  łańcucha  nazwy 
koloru karty z s do kol.

Karta::Karta(char* s,int w): wym(w)
{

strcpy(kol,s);

background image

 

 

Wiersze 34-36: definicja funkcji własnej klasy Karta o 
nazwie Druk(). Jest ona wykonywana w bloku main() na 
rzecz obiektów k1 oraz k2. To, że jest ona funkcją własną 
klasy Karta wskazuje nazwa klasy rozpoczynająca 
definicję i operator zakresu :: , który wskazuje, że funkcja 
działa w całym zakresie ważności klasy. Funkcja Druk() 
wykonuje na ekranie wypisanie nazwy koloru karty i jej 
wartości punktowej. 

void Karta::Druk()
{
cout<<”\nkolor=”<<kol<<”,wymiar=”<<wym;

k1.Druk();
k2.Druk();

background image

 

 

Kolor obiektu k1 jest modyfikowany w wierszu 18 
funkcją strcpy. W składni wymienia się nazwę 
obiektu, a po kropce nazwę argumentu 
zmienianego. W wierszu 19 modyfikowany jest 
argument wym obiektu k2 poprzez zwykłą operację 
przypisania nowej wartości. 

k1.Druk();
k2.Druk();
strcpy(k1.kol,”czarno-czerwona”);
k2.wym=28;

WNIOSEK: 

Klasa a obiekt

Widać, że 

klasa nie definiuje konkretnych 

obiektów tylko ich typy

!!! Jest ona typem 

obiektu jako abstrakcyjnej zmiennej, a nie 
obiektem lub zbiorem obiektów

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 wiec 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

 

 

Przykład: Konstruktor domniemany 

#include 
<iostream.h>
#include <conio.h>
#include <string.h>
#include <dos.h>
class X
{
public:
char kol[80];
int wym;

X(char* s=“?”, int 
w=-1);

void Druk();
}; 

#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <dos.h>
class Karta
{
public:
char kol[80];
int wym;

Karta(char*, int);

void Druk();
};

 

background image

 

 

void main()
{
clsscr();

X k1,k2(“fiolet”);

k1.Druk();
k2.Druk();
strcpy(k1.kol,”biala”);
strcpy(k2.kol, k1.kol);
k1.wym+=10;
k2.wym=k1.wym*5;
cout<<endl;

k1.Druk();
k2.Druk();
cout<<”\n\n”<,”size=”<<si
zeof(k1);
cout<<”\n\n”<,”size=”<<si
zeof(X);
 
getch();
}

void main()
{
clsscr();

Karta 
k1(“czarna”,5),k2(“czerwona”,8);

k1.Druk();
k2.Druk();
strcpy(k1.kol,”czarno-
czerwona”);
k2.wym=28;
cout<<endl;

k1.Druk();
k2.Druk();
getch();
}

background image

 

 

X::X(char* s,int w)
{
wym=w;
strcpy(kol,s);
}
void X::Druk()
{
cout<<”\nkolor=”<<kol<<”,w
ymiar=”<<wym;
}

Karta::Karta(char* s,int w): 
wym(w)
{
strcpy(kol,s);
}
void Karta::Druk()
{
cout<<”\nkolor=”<<kol<<”,wy
miar=”<<wym;
}

background image

 

 

Cechy obiektów

• Poprzez sposób definiowania obiektu decydujemy o zakresie 

ważności jego nazwy czyli także o czasie jego życia.

• Jeśli obiekt jest definiowany w dostępie publicznym to 

rozumiemy, że jest dostępny globalnie (uwaga na Grębosza 

i pomyłkę pomiędzy pojęciem zmiennej typu wbudowanego 

i obiektem) czyli mogą z niego korzystać wszystkie funkcje i 

obiekty innych klas w programie.

• Obiekt może funkcjonować lokalnie (obiekt prywatny) i 

wówczas automatycznie kończy się jego zakres ważności 

wtedy, kiedy fragment programu (klasa, blok) pozostaje 

zakończona faktycznie. Taki obiekt –podobnie jak zmienna 

lokalna – traci swoje cechy (pomimo hermetyzacji) w 

zakresie wartości jego zmiennych i metod. Taki obiekt, 

podobnie jak zmienną lokalną, będziemy uważać za 

zapisywany automatycznie.

background image

 

 

Cechy obiektów

• Obiekt globalny jest inicjalizowany inaczej niż lokalny bo 

wstępnie (zanim zacznie funkcjonować jako konkret) jest 
inicjowany zerami.

• Obiekt mogę powołać do życia jako obdarzony atrybutami. W 

szczególności może to być atrybut static. Taki obiekt, nawet 
jeśli jest lokalny, zachowa swoje wartości zmiennych i metod 
takie, jak przy ostatnim komunikacie. Inicjalizacja jest tu 
podobna jak obiektu globalnego – wartościami zerowymi.

• Jeśli atrybutu static użyjemy do nazwy globalnej, to może 

ona być dostępna TYLKO W SWOIM PLIKU. Oznacza to, że 
nie mogę uzyskać dostępu do takiego obiektu wtedy, kiedy 
jest on w pliku dołączonym dyrektywą preprocesora include 
jako plik nagłówkowy.


Document Outline