C ++ Polimorfizm və Virtual İşləmə

C ++ dilində polimorfizm



Polimorfizm sözü bir çox formaya sahib olmaq deməkdir

Polimorfizmdən istifadə edərək fərqli kontekstdə bir şeyə fərqli məna və ya istifadə təyin edə bilərik - konkret olaraq dəyişən, funksiya və ya obyekt kimi bir varlığın birdən çox formaya sahib olmasına imkan verir. Polimorfizmin müxtəlif növləri var.

Object Orient Programming-də polimorfizm eyni funksiyaların birdən çox tətbiqetmə imkanını təmsil edir. Sadə bir polimorfizm nümunəsini “C ++ Həddindən artıq yükləmə” də görə bilərsiniz. Eyni ada malik bir funksiya, çağırış kontekstinə görə fərqli davranışlara sahib ola bilər. Polimorfizmin ən maraqlı anlayışları Mirasla əlaqədardır. Təməl sinifin göstəricisi kimi əsas sinif göstəricisi istifadə edilə bilər. Dərslərin aşağıdakı iyerarxiyasına baxın:

class baseClass
{
public:
	baseClass(int val) :someValue(val)
	{

	}
	void info()
	{
		cout << "Info member function of base class" << endl;
	}
protected:
	int someValue;
};

class derivedClass1 : public baseClass
{
public:
	derivedClass1(int val) :baseClass(val)
	{

	}
	void info()
	{
		cout << "Info member function of derived class 1" << endl;
	}
};

class derivedClass2 : public baseClass
{
public:
	derivedClass2(int val) :baseClass(val)
	{

	}
	void info()
	{
		cout << "Info member function of derived class 2" << endl;
	}
};


 

Bir baza sinifinin göstəricisini, əldə edilən sinifin göstəricisi kimi istifadə edə bilərik:

	
derivedClass1 child1(1);
derivedClass2 child2(2);

//pointers to base class
baseClass* basePtr1;
baseClass* basePtr2;

//make pointers to base class point to objects of derived classes
basePtr1 = &child1;
basePtr2 = &child2;

Təməl sinifin göstəriciləri kimi əsas sinif göstəricilərindən istifadə etmək çox asan görünür. Ancaq problem nə vaxt ortaya çıxır

  • Əsas sinifdə mövcud olmayan bir törəmə sinifin üzv funksiyasını və ya çağırmaq istəyirik
  • Çağırmaq istədiyimiz funksiya əldə edilən sinifdə ləğv olunur

Əsas sinif və iki növ sinif eyni funksiyaya malikdir məlumat (). Aşağıdakı kimi baza sinfi üçün göstərici istifadə edərək bu funksiyanı çağırmağa çalışın:

//calling info function
basePtr1->info();
basePtr2->info();

Bu halda, əldə edilmiş siniflərin info () üzvü funksiyası çağırılmayacaqdır. Bunun əvəzinə baza sinfinin info () funksiyası çağırılacaq. Aşağıda yuxarıdakı zənglərin nəticəsi verilmişdir:

Əsas sinif məlumat üzvü funksiyası
Əsas sinif məlumat üzvü funksiyası

Statik Oyuncu

Əsas sinfin göstəricisi ilə törəmə sinifin göstəricisi kimi işləmək üçün statik yayımdan istifadə edə bilərik:

//use static cast and call info from derived class 1
static_cast<derivedClass1*> (basePtr1)->info();

Bu halda, derivedClass1-dən üzv funksiyası məlumatı () deyiləcəkdir:

Alınan sinif 1 məlumat üzvü funksiyası

Virtual funksiyalar

Virtual funksiyalar, əldə edilən sinifdə ləğv edilməsi gözlənilən funksiyalardır. Virtual funksiyanı istifadə edərək, baza sinfinin göstəricisindən istifadə edərək bir törəmə sinifin funksiyalarına zəng edə bilərik.

Virtual funksiyanın bəyannaməsi istifadə etməklə edilir virtual aşağıda göstərildiyi kimi bir funksiyanın elanından əvvəl açar söz:

virtual function-declaration;

BaseClass funksiyası məlumatını () virtual funksiya olaraq elan etməyə çalışın:
virtual void info()
{
	cout << "Info member function of base class" << endl;
}

İndi əsas sinif göstəricisini istifadə edərək məlumat funksiyasını axtarmağa çalışın:
derivedClass1 child1(1);
derivedClass2 child2(2);

//pointers to base class
baseClass* basePtr1;
baseClass* basePtr2;

//make pointers to base class point to objects of derived classes
basePtr1 = &child1;
basePtr2 = &child2;

//call info
basePtr1->info();
basePtr2->info();

Hər bir çıxarılan sinfin uyğun üzv funksiyası heç bir atış olmadan çağırılacaq, sonra nəticə olacaqdır:

Alınan sinif 1 məlumat üzvü funksiyası
Alınan sinif 2 məlumat üzvü funksiyası

İnfo () üzv funksiyasını derivedClass1-dən silməyə çalışın və bu kodu yenidən tərtib edin, sonra nəticə çıxacaq:

Əsas sinif məlumat üzvü funksiyası
Alınan sinif 2 məlumat üzvü funksiyası

Gördüyünüz kimi, kompilyator əvvəlcə müvafiq törədilmiş sinifdə info () üzvü funksiyasını axtarır. Törədilən sinifdə üzv funksiyasını tapa bilmirsə, əsas sinifin üzv funksiyasını çağıracaqdır.

Gec bağlama (İşləmə Polimorfizmi)

Gec bağlama ayrıca Dinamik Bağlama və ya Çalışma Zamanı Bağlama kimi də bilinir.

Bəzən tərtibçi proqram icra olunana qədər (işləmə müddəti) hansı funksiyanın çağırılacağını bilmir. Bu gec bağlama kimi tanınır.

Cild kompilyator tərəfindən identifikatorları (dəyişən və funksiya adları kimi) maşın dilinin ünvanlarına çevirmək üçün istifadə olunan prosesdir.

Bir obyektin çağırdığı metodun iş vaxtında adla əlaqələndirildiyi bir mexanizmdir. Gec bağlama nə zaman olur virtual açar söz üzv funksiyası elanında istifadə olunur.

Gec bağlama mexanizmi

C ++ virtual funksiyalarının tətbiqi olaraq bilinən gec bağlama xüsusi bir forması istifadə olunur virtual masa (VCədvəl). Bir sinif virtual üzv funksiyasını elan etdikdə, tərtibçilərin çoxu bir işarəni təmsil edən gizli üzv dəyişən əlavə edirlər Virtual Metod Cədvəli (VMT or VCədvəl). Bu göstəricini belə adlandıracağıq vptr. Bu cədvəl virtual funksiyalar üçün bir sıra göstəriciləri əks etdirir. Tərtib zamanı hansı funksiyanın çağırılacağı barədə məlumat yoxdur. İş vaxtı, Virtual Metod Cədvəlindəki göstəricilər sağ funksiyaları göstərəcəkdir.

Aşağıdakı misala baxın:

class A
{
public:
	virtual void function1() {};
	virtual void function2() {};
};

class B : public A
{
public:
	virtual void function1() {};
};

class C : public A
{
public:
	virtual void function2() {};
};

Hər hansı bir sinifin bir obyekti yaradıldıqda, VMT üçün öz göstəricisinə sahibdir:

VCədvəlPin

Bir obyekt obyektdən çağırıldıqda, həmin obyektin müvafiq VMT-sində görünəcəkdir.

Virtual Dağıdıcı

Bir obyekt məhv edildikdə dağıdıcı deyilir. C ++ bütün siniflər üçün standart destruktor təqdim edir. Bununla birlikdə, bəzən özünüzün məhvedicinizi yaratmağa ehtiyac var. Yaddaş bölüşdürməyiniz, bir qaynaq azad etməyiniz və s. Lazım olduqda edilə bilər.

Dərslər hiyerarşiniz olduqda, virtual destruktorlardan istifadə etməyiniz tövsiyə olunur. Virtual Destructor Bəyannaməsi aşağıdakı şəkildə görünür:

virtual ~ClassName()

Niyə virtual destruktorlardan istifadə etmək lazımdır?

Virtual Destructor olmadan yayım

Aşağıdakı misala baxın:

class A
{
public:
	~A()
	{
		cout << "Base class destructor" << endl;
	}
};

class B : public A
{
public:
	~B()
	{
		cout << "B class destructor" << endl;
	}
};

int main()
{
	A* a = new B;
	delete a;
}

Gördüyünüz kimi “a” göstəricisi B tipli bir obyektə işarə edir. “A” silinəndə yalnız baza sinfinin destruktoru çağırılacaq. Bu o deməkdir ki, əldə edilmiş bir sinfin obyekti lazımi şəkildə məhv edilməyəcəkdir.

Bu problem Virtual Destructor ilə asanlıqla həll olunur.

Virtual Destructor ilə yayımlanır

Əsas sinif destruktorunu virtual (ilə) dəyişdirərək əvvəlki nümunəni dəyişdirməyə çalışın.tökmək):

class A
{
public:
	virtual ~A()
	{
		cout << "Base class destructor" << endl;
	}
};

class B : public A
{
public:
	~B()
	{
		cout << "B class destructor" << endl;
	}
};

int main()
{
	A* a = new B;
	delete a;
}

Baza sinfi destruktoru virtual olduqda, əvvəlcə əldə edilən sinif destruktoru deyilir və bundan sonra baza sinfi destruktoru deyilir:

B sinif destruktoru
Əsas sinif destruktoru

Abstract Class və Saf Virtual Funksiya

Translate »