C++

Siniflər

Siniflər

Paraqraf 8-də biz struct tiplər ilə tanış olduq. Qeyd elədik ki, struct tiplər proqramçı tərəfindən yaradılan yeni tiplərdir və bu tiplərdən biz, digər standart tiplərdən olduğu dəyişənlər elan edə bilərik. C++ dilinin adı çəkiləndə yada düşən ilk anlayış bizim yeni daxil edəcəyimiz sinif anlayışıdır. Burada qeyri-adi, yeni heç bir şey yoxdur. Sadəcə olaraq, siniflərə strukt tiplərin bir az fərqli və inkişaf etmiş növü kimi baxmaq olar. Belə ki, strukt tipinin elementlərini tərtib edərkən, biz standart tiplərdən və əvvəl yaratdığımız strukt tiplərdən istifadə edirdik. Bu qayda siniflər üçün də keçərlidir. Lakin siniflərin strukt tiplərdən fundamental üstünlüyü ondadır ki, biz siniflərin tərkibinə nəinki hər hansısa tipdən olan dəyişən, hətta funksiyaları da daxil edə bilərik. (C dilində sinif təyin olunmur, amma strukt daxilində funksiya elan etməyə imkan var) Siniflərdən istfadə etməklə tərtib olunmuş sadə nümunə proqram fikirlərimizə daha da aydınlıq gətirər.

Proqram nümunəsi:


// prg_10_1.cpp 

#include <iostream> 

// sadə_sinif tipini elan edirik 

class sadə_sinif{ 
public: 
int x; 
int y; 
int cəm(void ); 
}; 

// sadə_sinif-in cəm funksiyasının mətn kodu 
int sadə_sinif::cəm(void ) 
{ 
return x+y; 
} 

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
int main(){ 

// yeni tərtib etdiyimiz sinif tipindən dey1 adlı dəyişən elan edirik 
// sinif tipindən olan dəyişən nümunələrinə "obyekt" deyilir. 
sadə_sinif dey1; 

//dey1 obyektinin hədlərinə qiymətlər mənimsədirik 
dey1.x = 5 ; 
dey1.y = 10 ; 

//dey1 obyektinin cəm funksiyasına müraciət edirik 
std::cout<<"dey1 obyektinin x və y hədlərinin cəmi = "  
<<dey1.cəm()<<" \n " ; 

return  0 ; 
}

Nümunə

Proqramın izahı:

Gəlin, yuxarıda daxil etdiyimiz proqramı analiz edək, daha sonra siniflərlə bağlı digər proqram nümunələrinə baxarıq. Yeni sinif tipi yaradarkən, class sözündən istifadə edirik. Daha sonra isə, yeni yaratmaq istədiyimiz sinif tipinin adını yazırıq.

Aşağıdakı kimi:

class sinif_adı

Sinfin adını dəyişənləri adlandırdığımız kimi adlandıra bilərik. Daha sonra isə, { mötərizəsini yerləşdiririk. Nümunə proqramda bu class sadə_sinif{ sətrinə uyğun gəlir. { mötərizəsindən sonra sinfi təşkil edən elementlər - dəyişənlər və funksiyalar yerləşdirilir. Sinfin sonunu bildirmək üçün } mötərizəsindən və sintaksis tələbi olan ; -dən istifadə olunur.

Baxdığımız sinifdə biz int tipli x və y dəyişənləri, int tipli nəticə qaytaran cem funksiyası elan etmişik.

class sadə_sinif{

public:

int x;

int y;

int cəm(void);

};

public ifadəsinin mənasını irəlidə daxil edəcəyik.

Beləliklə, biz artıq sadə_sinif adlı yeni class tipi elan etmişik. Yeni sinif tipi yaradarkən, yerinə yetirməli olduğumuz ikinci iş sinfin funksiya hədlərinin mətn kodunu tərtib etməkdir. Sinfin funksiya hədlərinin mətn kodu adi funksiyaların mətn kodu kimi tərtib olunur, sadəcə funksiyanın hansı sinfə məxsus olduğunu bildirmək üçün funksiyanın adının əvvəlinə sinif_adı:: ifadəsi yazırıq.

Nümunə proqramında bu int sadə_sinif::cəm(void){ sətrinə uyğun gəlir. Daha sonra isə, adi qaydada olduğu kimi funksiyanın mətn kodunu tərtib edirik. Bizim daxil etdiyimiz funksiyanın mətn kodu bir sətirdən ibarətdir return x+y; .

x və y dəyişənləri cəm funksiyasına nə parametr kimi ötürülüb, nə də onun daxilində dəyişən kimi elan olunublar. Bəs cəm funksiyası x və y dəyişənlərini necə tanıdı və onların qiymətlərini haradan götürdü?

Burada siniflərin aşağıdakı xassəsindən istifadə olunur:

Sinfin funksiya hədləri onun dəyişən hədlərinə birbaşa müraciət edə bilər. cəm funksiyası daxilində istifadə olunan x və y dəyişənləri məhs sinfə məxsusdur. Sinfin elementlərini daxil etdikdən və funksiya hədlərinin mətn kodunu tərtib etdikdən sonra, biz artıq yeni yaratdığımız sinif tipindən dəyişənlər elan edə bilərik, adi tiplərdən olduğu kimi.

Nümunə proqramın main funksiyasında biz sade_sinif tipinidən dey1 adlı dəyişən elan edirik, aşağıdakı kimi:

sadə_sinif dey1;

Struct tipində olduğu kimi, class tipində də hədlərə müraciət etmək üçün nöqtə (.) operatorundan istifadə olunur. Misal üçün, kvadrat sinfinin tərəf həddinə müraciət etmək üçün kvadrat.tərəf yazırıq. Proqramda biz dey1 obyektinin x və y hədlərinə müvafiq olaraq 5 və 10 qiymətləri mənimsətmişik, aşağıdakı kimi:

dey1.x = 5;

dey1.y = 10;

Daha sonra isə, dey1 obyektinin cem funksiya həddinə müraciət olunur hansı ki, öz növbəsində dey1 obyektinin x və y hədlərinin cəmini nəticə olaraq qaytarır. Bu baxdığımız sadə nümunədə biz yeni sinif tipi elan etməyi, onun funksiya hədlərinin mətn kodunu tərtib etməyi və eləcə də, sinfin dəyişən və funksiya hədlərinə müraciət etməni öyrəndik. Bu, siniflər barəsində bilməli olduğumuz zəruri anlayışlar idi. İndi isə, siniflərlə bağlı digər anlayışları və istifadə qaydalarını daxil edək.

 

10.1 Açıq və gizli hədlər

Sinif tipinin strukt tipindən digər fərqi də odur ki, sinif tipinin hədləri açıq və gizli ola bilər. Sinfin açıq hədlərinə proqramın istənilən funsiyasından müraciət etmək olar, gizli hədlərə isə, yalnız və yalnız sinfin öz funksiyaları müraciət edə bilər. Sinfin hər hansı həddini açıq elan etmək üçün public: ifadəsindən istifadə edirlər.

Bu zaman sinif daxilində public: ifadəsindən sonra yerləşdirilmiş hədlər açıq olurlar. Sinfin hədlərini gizli elan etmək üçün private: ifadəsindən istifadə olunur. Sinfin elanı daxilində açıq və gizli hədlərin hansı ardıcıllıqla yerləşdirilməsi ilə bağlı heç bir məhdudiyyət yoxdur. Gəlin, daxil etdiyimiz bu yeni anlayışlara aid proqram nümunəsi ilə tanış olaq.

Proqram nümunəsi:


// prg_10_2.cpp

#include <iostream>

// düzbucaqlı tipini elan edirik

class düzbucaqlı
{
public:
void tərəflər(int,int);
int sahə(void);

private:
int en;
int uzunluq;
};

// düzbucaqlı-nın tərəflər funksiyasının mətn kodu
// klasın en və uzunluq gizli hədlərini qiymətləndiririk
void düzbucaqlı::tərəflər(int x,int y)
{
en = x;
uzunluq = y;
}

// düzbucaqlı-nın sahə funksiyasının mətn kodu
int düzbucaqlı::sahə(void)
{
return en*uzunluq;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{

düzbucaqlı düzb1;

// düz1-in en və uzunluğuna qiymətlər mənimsədək
düzb1.tərəflər(5,8);

// düzb1-in sahəsini çap edək
std::cout<<"düzbucaqlının sahəsi = "<<düzb1.sahə()<<"\n";

return 0;
}

Nümunə

Nəticə:


C:\cpp\prog2\Debug> 
C:\cpp\prog2\Debug>./prog2.exe 
düzbucaqlının sahəsi = 40 
C:\cpp\prog2\Debug> 
C:\cpp\prog2\Debug>

10.2 Konstruktor və Destruktor

Yuxarıda baxdığımız sinif2.cpp proqramında biz düzbucaqlı sinfindən duzb1 obyekti yaradırıq. Daha sonra, bu obyektin en və uzunluq-unu mənimsətmək üçün terefler funksiya həddini çağırırıq.

Obyekt yönümlü proqramlaşdırmada bir çox hallarda obyektin hədlərinin qiymətlərini obyekt yaradılarkən mənimsətmək tələb olunur. Bunun üçün konstruktor adlandırılan funksiyadan istifadə olunur, hansı ki, obyekt yaradılarkən avtomatik çağırılır. "Obyekt yaradılarkən" deyəndə verilmiş sinif tipindən hər hansı dəyişənin elan olunması nəzərdə tutulur. Misal üçün, yuxarıdakı nümunə proqramda düzbucaqlı düzb1; sətrində düzb1 obyekti yaradılır və əgər biz düzbucaqlı sinfi üçün konstruktor təyin etsəydik, onda o, avtomatik çağırılardı.

 

10.3 Konstruktorun təyin olunması

Hər hansı sinfin konstruktorunu təyin etmək üçün bu sinif daxilində həmin sinfin adı ilə üst-üstə düşən funksiya təyin etmək lazımdır. Bu funksiyaya sinfin qurucusu - konstruktoru deyilir. Qurucu funksiyasının məqsədi sinfin hədlərinin ilkin qiymətlərini mənimsətməkdir. Gəlin, yuxarıda daxil etdiyimiz sinif2.cpp proqramının sinifdən istifadə etməklə variantını daxil edək.

Proqram nümunəsi:


// prg_10_3.cpp

#include <iostream>

// düzbucaqlı tipini elan edirik
class düzbucaqlı
{
public:
düzbucaqlı();
void tərəflər(int,int);
int sahə(void);

private:
int en;
int uzunluq;
};

// qurucu - konstruktor
düzbucaqlı::düzbucaqlı()
{
en = 10;
uzunluq = 15;
}

// düzbucaqlının tərəflər funksiyasının mətn kodu
// sinfin en və uzunluq gizli hədlərini qiymətləndiririk
void düzbucaqlı::tərəflər(int x,int y)
{
en = x;
uzunluq = y;
}

// düzbucaqlının sahə funksiyasının mətn kodu
int düzbucaqlı::sahə(void)
{
return en*uzunluq;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

int main(){

düzbucaqlı düzb1;

// qurucu avtomatik çağırılır və hədlərə qiymətlər mənimsədir
// bunu sahə funksiyasını çağırmaqla yoxlaya bilərik
std::cout<<"düzbucaqlının sahəsi = "<<düzb1.sahə()<<"\n";

// düzb1-in tərəflərinə ayrı qiymətlər mənimsədək
düzb1.tərəflər(5,8);

std::cout<<"düzbucaqlının sahəsi = "<<düzb1.sahə()<<"\n";

return 0;
}

Nümunə

Nəticə:


C:\cpp\prog2\Debug> 
C:\cpp\prog2\Debug>./prog2.exe 
düzbucaqlının sahəsi = 150 
düzbucaqlının sahəsi = 40 
C:\cpp\prog2\Debug> 
C:\cpp\prog2\Debug>

10.4 Destruktorun təyin olunması

Destruktor funksiyası konstruktorun əksinə olaraq, obyekt yaddaşdan silindiyi zaman çağırılır. Bu funksiya da sinfin adı ilə eyni adlandırılır, yalnız adın əvvəlinə ~ işarəsi artırılır. Destruktorlar əsasən dinamik yaradılan obyektlər (ünvan tipli sinif dəyişənləri) yaddaşdan silinərkən avtomatik çağırlır, lakin əgər biz obyekti özümüz istədiyimiz vaxt məhv etmək istəsək, onda onun destruktorunu çağırırıq.

 

10.5 Obyektlərin dinamik yaradılması və silinməsi

Növbə çatdı ünvan dəyişənləri barəsində öyrəndiyimiz biliklərin siniflərə tətbiqinə. §4-də qeyd eləmişdik ki, statik dəyişənlər elan olunan zaman onlara yaddaşda yer ayrılır və bu yeri sonradan həmin dəyişəndən azad edib başqa məqsədlər üçün istifadə etmək mümkün deyil.

Bu səbəbdən də, iri həcmli dəyişənlərdən istifadə olunan zaman adi dəyişənlərdən istifadə etmək proqramın məhsuldarlığını aşağı salır, dinamik dəyişənlər isə əksinə. Yuxarıda baxdığımız nümunə proqramda biz düzbucaqlı sinfindən adi dəyişən elan etmişdik.

Gəlin, indi həmin proqramın unvan tipli dəyişəndən (dinamik) istifadə edilən halına baxaq. Proqrama baxmazdan öncə onu da qeyd edək ki, (bax §8.1) dinamik obyektin funksiya və dəyişən hədlərinə müraciət etmək üçün . yox -> operatorundan istifadə olunur.

Proqram nümunəsi:


// prg_10_4.cpp

#include <iostream>

// düzbucaqlı tipini elan edirik
class düzbucaqlı
{
public:
düzbucaqlı();
void tərəflər(int,int);
int sahə(void);

private:
int en;
int uzunluq;
};

// konstruktor
düzbucaqlı::düzbucaqlı()
{
en = 10;
uzunluq = 15;
}

// düzbucaqlının tərəflər funksiyasının mətn kodu
// klasın en və uzunluq gizli hədlərini qiymətləndiririk
void düzbucaqlı::tərəflər(int x,int y)
{
en = x;
uzunluq = y;
}

// düzbucaqlının sahə funksiyasının mətn kodu
int düzbucaqlı::sahə(void)
{
return en*uzunluq;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{

düzbucaqlı *düzb1;

// hələ ki, yaddaşda düzb1 üçün heç bir yer ayrılmayıb
// düzb1-ı yaradaq
düzb1 = new düzbucaqlı;

// konstruktor avtomatik çağırılır
std::cout<<"düzbucaqlının sahəsi = "<<duzb1->sahe()<<"\n";

// düzb1-ın tərəflərinə ayrı qiymətlər mənimsədək
duzb1->tərəflər(5,8);
std::cout<<"düzbucaqlının sahəsi = "<<düzb1->sahə()<<"\n";

return 0;
}

Nümunə

Nəticə:


C:\cpp\prog2\Debug> 
C:\cpp\prog2\Debug>./prog2.exe 
düzbucaqlının sahəsi = 150 
düzbucaqlının sahəsi = 40 
C:\cpp\prog2\Debug> 
C:\cpp\prog2\Debug>