C++ Polimorfizmus példával

⚡ Okos összefoglaló

Polimorfizmus be C++ lehetővé teszi, hogy egy tagfüggvény számos formát öltsön, és a meghívott objektumtól függően eltérően viselkedjen. Az öröklődésre épül, és kétféle változatban jelenik meg, amelyeket fordítási vagy futási időben oldanak fel.

  • 🔷 Meghatározás: A polimorfizmus „sokféle formát” jelent, amely lehetővé teszi, hogy egy tagfüggvény a hívó objektumtól függően eltérően viselkedjen.
  • 🧭 Két típus létezik: C++ fordítási idejű (statikus) és futási idejű (dinamikus) polimorfizmust biztosít.
  • 🧩 Fordítási idő: A függvények és az operátorok túlterhelése a fordítás során kiválasztja a megfelelő függvényt.
  • 🔁 Futási idő: A függvényfelülírás és a virtuális függvények a program végrehajtása közben oldják fel a hívást.
  • 🇧🇷 Virtuális függvények: Az alaposztály virtual kulcsszava lehetővé teszi a késői kötést egy alaposztály-mutatón keresztül.
  • 🤖 AI segítség: A GitHub Copilot és hasonló asszisztensek egy rövid megjegyzésből túlterhelt, felülírt és virtuális függvényeket állítanak össze.

C++ polimorfizmus

Miben rejlik a polimorfizmus? C++?

In C++A polimorfizmus hatására egy tagfüggvény eltérően viselkedik attól függően, hogy melyik objektum hívja meg/hívja. A polimorfizmus egy görög szó, ami azt jelenti, hogy sok alakja van. Akkor fordul elő, ha van egy hierarchiád a következőkből: osztályok öröklés útján rokonok.

Tegyük fel például, hogy a makeSound() függvényünk van. Amikor egy macska meghívja ezt a funkciót, nyávog hangot ad ki. Amikor egy tehén ugyanazt a funkciót hívja meg, a nyírás hangját adja.

Polimorfizmus be C++ makeSound példa

Bár egy funkciónk van, másképpen viselkedik különböző körülmények között. A függvénynek számos formája van; így polimorfizmust értünk el.

A központi gondolattal a helyén, C++ két jól elkülönülő kategóriába sorolja ezt a viselkedést.

A polimorfizmus típusai

C++ kétféle polimorfizmust támogat:

  • Fordítási idejű polimorfizmus, és
  • Futásidejű polimorfizmus.

A polimorfizmus típusai C++

Az első kategória minden függvényhívást felold, mielőtt a program egyáltalán lefutna.

Fordítsa össze az időpolimorfizmust

A túlterhelt függvényeket az argumentumok számának és típusának egyeztetésével hívhatja meg. Az információ a fordítási idő alatt jelen van. Ez azt jelenti, hogy a C++ A fordító a fordításkor kiválasztja a megfelelő függvényt.

A fordítási idejű polimorfizmus a funkciók túlterhelésével és a kezelő túlterhelésével érhető el.

Funkció túlterhelés

A függvénytúlterhelés akkor fordul elő, ha sok hasonló nevű, de eltérő argumentumú függvényünk van. Az argumentumok számuk vagy típusuk szerint különbözhetnek.

Példa 1

#include <iostream> 
using namespace std;

void test(int i) {
	cout << " The int is " << i << endl;
}
void test(double  f) {
	cout << " The float is " << f << endl;
}
void test(char const *ch) {
	cout << " The char* is " << ch << endl;
}

int main() {
	test(5);
	test(5.5);
	test("five");
	return 0;
}

output:

C++ függvény túlterhelés 1. példa kimenet

Itt van egy képernyőkép a kódról:

C++ függvény túlterhelés 1. példa kód

Code Magyarázat:

  1. Szerelje be az iostream fejlécfájlt a kódunkba. Használni tudjuk majd a funkcióit.
  2. Szerelje be az std névteret a kódunkba. Az osztályait használhatjuk anélkül, hogy meghívnánk.
  3. Hozzon létre egy teszt nevű függvényt, amely egy i egész paramétert vesz fel. A { jelzi a funkcióteszt törzsének kezdetét.
  4. A fenti funkcióteszt meghívása/meghívása esetén végrehajtandó utasítás.
  5. A fenti funkcióteszt törzsének vége.
  6. Hozzon létre egy teszt nevű függvényt, amely egy f lebegő paramétert vesz fel. A { jelzi a funkcióteszt törzsének kezdetét.
  7. A fenti funkcióteszt meghívása/meghívása esetén végrehajtandó utasítás.
  8. A fenti funkcióteszt törzsének vége.
  9. Hozzon létre egy teszt nevű függvényt, amely egy ch karakterparamétert vesz fel. A { jelzi a funkcióteszt törzsének kezdetét.
  10. A fenti funkcióteszt meghívása/meghívása esetén végrehajtandó utasítás.
  11. A fenti funkcióteszt törzsének vége.
  12. Hívja meg a main() függvényt. A { a függvény törzsének kezdetét jelöli.
  13. Hívja meg a függvénytesztet, és adja meg az 5-öt az argumentum értékeként. Ez meghívja az egész argumentumot elfogadó tesztfüggvényt, azaz az első tesztfüggvényt.
  14. Hívja meg a függvénytesztet, és adja át neki az 5.5-öt az argumentum értékeként. Ez meghívja a lebegő argumentumot elfogadó tesztfüggvényt, vagyis a második tesztfüggvényt.
  15. Hívja meg a függvénytesztet, és adjon át neki ötöt az argumentum értékeként. Ez meghívja a karakter argumentumot elfogadó tesztfüggvényt, azaz a harmadik tesztfüggvényt.
  16. A programnak értéket kell visszaadnia, ha sikeresen fut.
  17. A main() függvény törzsének vége.

Három függvényünk van azonos névvel, de különböző típusú argumentumokkal. Elértük a polimorfizmust.

Operator Túlterhelés

In Operator Túlterhelés, új jelentést definiálunk a C++ operátor. Ez megváltoztatja az operátor működését is. Például definiálhatjuk a + operátort két karakterlánc összefűzésére. Ezt numerikus értékek összeadására szolgáló összeadó operátorként ismerjük. A definíciónk szerint, ha egész számok közé helyezzük, akkor összeadja azokat. Ha karakterláncok közé helyezzük, akkor összefűzi őket.

Példa 2

#include<iostream> 
using namespace std;

class ComplexNum {
private:
	int real, over;
public:
	ComplexNum(int rl = 0, int ov = 0) {
		real = rl;   
		over = ov; 
	}

	ComplexNum operator + (ComplexNum const &obj) {
		ComplexNum result;
		result.real = real + obj.real;
		result.over = over + obj.over;
		return result;
	}
	void print() { 
		cout << real << " + i" << over << endl; 
	}
};
int main()
{
	ComplexNum c1(10, 2), c2(3, 7);
	ComplexNum c3 = c1+c2;
	c3.print();
}

output:

C++ operátor túlterhelés 2. példa kimenet

Itt van egy képernyőkép a kódról:

C++ operátor túlterhelés 2. példa kód

C++ operátor túlterhelés 2. példa eredménye

Code Magyarázat:

  1. Szerelje be az iostream fejlécfájlt a programunkba, hogy használni tudja a funkcióit.
  2. Szerelje be az std névteret a programunkba, hogy az osztályait hívás nélkül használhassa.
  3. Hozzon létre egy ComplexNum nevű osztályt. A { az osztálytörzs kezdetét jelöli.
  4. A privát hozzáférés módosítóval jelölje meg a változókat privátként, vagyis csak az osztályon belülről lehet hozzáférni.
  5. Határozzon meg két egész változót, valós és over.
  6. A public access módosítóval jelöld meg a konstruktort nyilvánosként, ami azt jelenti, hogy az osztályon kívülről is elérhető lesz.
  7. Hozzuk létre az osztálykonstruktort és inicializáljuk a változókat.
  8. Inicializálja a real változó értékét.
  9. Inicializálja a változó értékét over.
  10. A kivitelező test vége.
  11. Felül kell írnunk a + operátor jelentését.
  12. Hozzon létre egy ComplexNum típusú adattípus eredményt.
  13. Komplex számokhoz használja a + operátort. Ez a sor hozzáadja egy szám valós részét egy másik szám valós részéhez.
  14. Komplex számokhoz használja a + operátort. Ez a sor hozzáadja egy szám képzeletbeli részét egy másik szám képzeletbeli részéhez.
  15. A program sikeres végrehajtás után visszaadja az eredmény változó értékét.
  16. Vége a + operátor új jelentésének definíciójának, vagyis a túlterhelésnek.
  17. Hívja meg a print() metódust.
  18. Nyomtassa ki az új komplex számot, miután hozzáadta a konzolon.
  19. A print() függvény törzsének vége.
  20. A ComplexNum osztály törzsének vége.
  21. Hívja meg a main() függvényt.
  22. Adja át mind a valós, mind az összetett részek értékeit. A c1 első része hozzáadódik a c2 első részéhez, azaz a 10+3. A c1 második része hozzáadódik c második részéhez, azaz 2+7.
  23. Végezzen műveletet a túlterhelt + operátorral, és az eredményt a c3 változóban tárolja.
  24. Nyomtassa ki a c3 változó értékét a konzolon.
  25. A main() függvény törzsének vége.

Ahol a fordítási idejű polimorfizmus korán dönt, a második kategória a választást a végrehajtásig elhalasztja.

Futásidejű polimorfizmus

Ez akkor fordul elő, ha egy objektum metódusát futás közben hívják meg, nem pedig fordítási idő alatt. A futásidejű polimorfizmus a függvény felülbírálásával érhető el. A meghívandó/meghívandó függvény futás közben jön létre.

Funkció felülbírálása

A függvény felülbírálása akkor történik, ha az alaposztály egy függvénye új definíciót kap egy származtatott osztályban. Ekkor azt mondhatjuk, hogy az alapfunkciót felülírták.

Például:

#include <iostream>
using namespace std;
class Mammal {

public:
	void eat() {

		cout << "Mammals eat...";
	}

};

class Cow: public Mammal {

public:
	void eat() {

		cout << "Cows eat grass...";
	}
};
int main(void) {

	Cow c = Cow();

	c.eat();

	return 0;

}

output:

C++ funkció felülíró kimenet

Itt van egy képernyőkép a kódról:

C++ függvény felülíró kód

Code Magyarázat:

  1. A funkcióinak használatához importálja az iostream fejlécfájlt programunkba.
  2. Szerelje be az std névteret a programunkba, hogy az osztályait hívás nélkül használhassa.
  3. Hozz létre egy Mammal nevű osztályt. A { az osztálytörzs kezdetét jelöli.
  4. A nyilvános hozzáférés módosító segítségével állítsa be nyilvánosan elérhetővé a létrehozandó funkciót. Az osztályon kívülről is elérhető lesz.
  5. Hozzon létre egy nyilvános függvényt eat. A { a függvénytörzs kezdetét jelöli.
  6. Nyomtassa ki a cout függvényhez adott utasítást az eat() függvény meghívásakor.
  7. Az eat() függvény törzsének vége.
  8. Az emlős osztály testének vége.
  9. Hozzon létre egy Cow nevű osztályt, amely örökli az Emlős osztályt. A tehén a származtatott osztály, míg az emlős az alaposztály. A { az osztály kezdetét jelzi.
  10. A nyilvános hozzáférés módosító segítségével jelölje meg nyilvánosan elérhetőként a létrehozandó funkciót. Az osztályon kívülről is elérhető lesz.
  11. Az alaposztályban definiált eat() függvény felülírása. A { a függvénytörzs kezdetét jelöli.
  12. A függvény meghívásakor a konzolra nyomtatandó utasítás.
  13. Az eat() függvény törzsének vége.
  14. Vége az osztály testének Tehén.
  15. Hívja meg a main() függvényt. A { jelöli a függvény törzsének kezdetét.
  16. Hozzon létre egy példányt a Cow osztályból, és adja meg a nevet c.
  17. Hívja meg a Cow osztályban definiált eat() függvényt.
  18. A programnak értéket kell visszaadnia a sikeres befejezés után.
  19. A main() függvény vége.

C++ Virtuális funkció

A virtuális függvény egy másik módja a futásidejű polimorfizmus megvalósításának C++. Ez egy speciális függvény, amely egy alaposztályban van definiálva, és újradefiniálható a származtatott osztályban. Virtuális függvény deklarálásához a virtuális kulcsszót kell használni. A kulcsszónak meg kell előznie a függvény deklarációját az alaposztályban.

Ha egy virtuális függvényosztály öröklődik, a virtuális osztály újradefiniálja a virtuális függvényt, hogy megfeleljen az igényeinek. Például:

#include <iostream>  
using namespace std;
class ClassA {
		public:
		virtual void show() {
			cout << "The show() function in base class invoked..." << endl;
		}
	};
	class ClassB :public ClassA {
	public:
		void show() 	{
			cout << "The show() function in derived class invoked...";
		}
	};
	int main() {
		ClassA* a;   
		ClassB b;
		a = &b;
		a->show();      
	}

output:

C++ virtuális függvény kimenet

Itt van egy képernyőkép a kódról:

C++ virtuális függvénykód

Code Magyarázat:

  1. Szerelje be az iostream fejlécfájlt a kódba a funkcióinak használatához.
  2. Szerelje be az std névteret a kódunkba, hogy az osztályait hívás nélkül használhassa.
  3. Hozzon létre egy osztályt ClassA néven.
  4. A nyilvános hozzáférés módosító segítségével jelölje meg egy osztálytagot nyilvánosan elérhetőként.
  5. Hozzon létre egy show() nevű virtuális függvényt. Nyilvános funkció lesz.
  6. A show() meghívásakor nyomtatandó szöveg. A endl egy C++ kulcsszó, ami végsort jelent. Az egérkurzort a következő sorra mozgatja.
  7. A show() virtuális függvény törzsének vége.
  8. Az A osztály törzsének vége.
  9. Új osztály létrehozása ClassB néven, amely örökli az ClassA osztályt. Az A osztály lesz az alaposztály, míg a B osztály lesz a származtatott osztály.
  10. A nyilvános hozzáférés módosító segítségével jelölje meg egy osztálytagot nyilvánosan elérhetőként.
  11. Határozza meg újra az alaposztályból származó show() virtuális függvényt.
  12. A konzolra nyomtatandó szöveg a származtatott osztályban definiált show() függvény meghívásakor.
  13. A show() függvény törzsének vége.
  14. A származtatott osztály törzsének vége, ClassB.
  15. Hívja meg a main() függvényt. A program logikáját hozzá kell adni a törzséhez.
  16. Hozzon létre egy mutatóváltozót a néven. A ClassA nevű osztályra mutat.
  17. Hozzon létre egy példányt az osztályból ClassB néven. A példány neve b.
  18. Rendelje hozzá a tárolt értékeket a b címben az a változóban.
  19. A származtatott osztályban definiált show() függvény meghívása. A késői kötés végrehajtásra került.
  20. A main() függvény törzsének vége.

Miután mindkét mechanizmust lefedtük, az alábbi táblázat egymás mellett mutatja be őket.

Fordítási idő polimorfizmus vs. Futásidejű polimorfizmus

Íme a fő különbségek a kettő között:

Compile-time polimorfizmus Futásidejű polimorfizmus
Korai kötődési vagy statikus polimorfizmusnak is nevezik. Késői/dinamikus kötődésnek vagy dinamikus polimorfizmusnak is nevezik.
A metódus a fordítási idő alatt kerül meghívásra/meghívásra A metódust futás közben hívja/meghívja
Funkció túlterheléssel és kezelő túlterheléssel valósítható meg Metódusfelülíráson és virtuális függvényeken keresztül valósul meg
Példa, módszer túlterhelés. Sok módszernek lehet hasonló neve, de eltérő számú vagy típusú argumentum Példa, módszer felülbírálása. Sok módszernek hasonló neve és prototípusa lehet.
Gyorsabb végrehajtás, mivel a metódusok felderítése fordítási időben történik Lassabb végrehajtás, mivel a metódusok felderítése futásidőben történik.
Less rugalmasság biztosított a problémamegoldáshoz, mivel a fordítási idő alatt minden ismert. Nagy rugalmasság biztosított az összetett problémák megoldásához, mivel a módszereket futás közben fedezik fel.

GYIK

A túlterhelés több azonos nevű, de eltérő paraméterekkel rendelkező függvényt definiál, amelyek fordítási időben, öröklődés nélkül kerülnek feloldásra. A felülbírálás egy örökölt alaposztályú függvényt definiál újra ugyanazzal az aláírással egy származtatott osztályban, és futási időben, a függvény virtuálisként deklarálásakor kerül feloldásra.

Egy tisztán virtuális függvényt = 0-val deklarálunk, és az alaposztályban nincs törzse. Bármely osztály, amely tartalmazza ezt, absz.tract osztály, amely nem példányosítható közvetlenül, és a származtatott osztályokat arra kényszeríti, hogy saját implementációt biztosítsanak.

Amikor egy osztály virtuális függvényeket deklarál, a fordító egy virtuális táblázatot (vtable) épít fel függvénymutatókból. Minden objektum egy rejtett mutatót tárol a vtable osztályára, így egy alap osztályú mutató futásidőben a megfelelő felülírt függvényt hívja meg késői kötésen keresztül.

Igen. A sablonok lehetővé teszik, hogy egy függvény vagy osztály több adattípuson működjön, miközben a fordító típusspecifikus kódot generál a fordítás során. Ez az általános programozás a statikus polimorfizmus egy formája, amely kiegészíti a függvény- és operátor-túlterhelést.

Amikor egy származtatott objektumot egy alaposztályú pointeren keresztül törölünk, csak egy virtuális destruktor garantálja, hogy a származtatott destruktor is lefut. Enélkül a tisztítás hiányos és memóriavesztést okoz. Az alapdestruktor virtuális deklarálása polimorfikus viselkedést eredményez a destruktív objektumban.

A polimorfizmus lehetővé teszi, hogy egyetlen felület számos objektumtípust kezeljen, csökkentve a duplikált kódot és leegyszerűsítve a karbantartást. Támogatja a rugalmas, bővíthető terveket, ahol az új származtatott osztályok a meglévő kód módosítása nélkül csatlakoznak, és lehetővé teszi az alaposztályú mutatókra és referenciákra épülő hatékony minták létrehozását.

Igen. A mesterséges intelligencia által fejlesztett kódolási asszisztensek egy rövid kommentet túlterhelt függvényekké, virtuális alaposztályokká és származtatott felülbírálásokká alakítanak. Gyorsan kezelik az ismétlődő sablonkódokat, bár a generált kód fordítása előtt továbbra is ellenőrizni kell a virtuális kulcsszavakat, a függvényaláírásokat és a destruktor biztonságát.

Igen. GitHub másodpilóta Virtuális függvénydeklarációkat, származtatott osztályok felülbírálását és operátor-túlterhelést javasol gépelés közben. Felgyorsítja az öröklési hierarchiák sablonos működését, bár a fordítás előtt érdemes megerősíteni a virtuális kulcsszót, az egyező aláírásokat és korrigálni a késői kötési viselkedést.

Foglald össze ezt a bejegyzést a következőképpen: