C++ Polymorfism med exempel

Vad är polymorfism i C++?

In C++, gör polymorfism att en medlemsfunktion beter sig annorlunda baserat på objektet som anropar/anropar den. Polymorfism är ett grekiskt ord som betyder att ha många former. Det inträffar när du har en hierarki av klasser relaterade genom arv.

Anta till exempel att vi har funktionen makeSound(). När en katt anropar denna funktion kommer den att producera ett mjauljud. När en ko åberopar samma funktion, kommer den att ge klippljudet.

Polymorfism i C++

Även om vi har en funktion, beter sig den olika under olika omständigheter. Funktionen har många former; därför har vi uppnått polymorfism.

Typer av polymorfism

C++ stöder två typer av polymorfism:

  • Kompileringstidspolymorfism, och
  • Runtime polymorfism.

Typer av polymorfism

Kompilera tidspolymorfism

Du anropar de överbelastade funktionerna genom att matcha antalet och typen av argument. Informationen finns närvarande under kompileringstiden. Detta betyder C++ kompilatorn väljer rätt funktion vid kompilering.

Kompileringstidspolymorfism uppnås genom funktionsöverbelastning och operatörsöverbelastning.

Funktion Överbelastning

Funktionsöverbelastning uppstår när vi har många funktioner med liknande namn men olika argument. Argumenten kan skilja sig åt vad gäller antal eller typ.

Exempelvis 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;
}

Produktion:

Funktion Överbelastning

Här är en skärmdump av koden:

Funktion Överbelastning

Kodförklaring:

  1. Inkludera iostream-huvudfilen i vår kod. Vi kommer att kunna använda dess funktioner.
  2. Inkludera std-namnområdet i vår kod. Vi kommer att kunna använda dess klasser utan att ringa det.
  3. Skapa en funktion med namnet test som tar en heltalsparameter i. { markerar början av funktionstestet.
  4. Uttalandet som ska utföras om ovanstående funktionsteste anropas/anropas.
  5. Slutet på huvuddelen av ovanstående funktionstest.
  6. Skapa en funktion med namnet test som tar en flytparameter f. { markerar början av funktionstestet.
  7. Uttalandet som ska utföras om ovanstående funktionsteste anropas/anropas.
  8. Slutet på kroppen av ovanstående funktionstest.
  9. Skapa en funktion som heter test som tar en teckenparameter ch. { markerar början av funktionstestet.
  10. Uttalandet som ska utföras om ovanstående funktionsteste anropas/anropas.
  11. Slutet på kroppen av ovanstående funktionstest.
  12. Anropa main()-funktionen. { markerar början av funktionens brödtext.
  13. Anropa funktionstestet och skicka 5 till det som värdet på argumentet. Detta anropar testfunktionen som accepterar ett heltalsargument, det vill säga den första testfunktionen.
  14. Anropa funktionstestet och skicka 5.5 till det som värdet på argumentet. Detta kommer att anropa testfunktionen som accepterar ett flytargument, det vill säga den andra testfunktionen.
  15. Anropa funktionstestet och skicka fem till det som värdet på argumentet. Detta kommer att anropa testfunktionen som accepterar ett teckenargument, det vill säga den tredje testfunktionen.
  16. Programmet måste returnera ett värde om det körs framgångsrikt.
  17. Slutet på huvuddelen av funktionen main().

Vi har tre funktioner med samma namn men olika typer av argument. Vi har uppnått polymorfism.

Operator överbelastning

In OperaFör överbelastning definierar vi en ny betydelse för en C++ operatör. Det förändrar också hur operatören arbetar. Till exempel kan vi definiera operatorn + för att sammanfoga två strängar. Vi känner till det som additionsoperatorn för att lägga till numeriska värden. Efter vår definition, när den placeras mellan heltal, kommer den att lägga till dem. När den placeras mellan strängar kommer den att sammanfoga dem.

Exempelvis 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();
}

Produktion:

Operator överbelastning

Här är en skärmdump av koden:

Operator överbelastning

Operator överbelastning

Kodförklaring:

  1. Inkludera iostream-huvudfilen i vårt program för att kunna använda dess funktioner.
  2. Inkludera std-namnområdet i vårt program för att kunna använda dess klasser utan att anropa det.
  3. Skapa en klass med namnet ComplexNum. { markerar början av klasskroppen.
  4. Använd modifieraren för privat åtkomst för att markera variabler som privata, vilket innebär att de bara kan nås från klassen.
  5. Definiera två heltalsvariabler, reella och över.
  6. Använd public access-modifieraren för att markera konstruktören som offentlig, vilket betyder att den kommer att vara tillgänglig även utanför klass.
  7. Skapa klasskonstruktorn och initiera variablerna.
  8. Initiera värdet på variabeln real.
  9. Initiera värdet på variabeln över.
  10. Slutet på konstruktorkroppen.
  11. Vi måste åsidosätta innebörden av +-operatorn.
  12. Skapa datatypresultatet av typen ComplexNum.
  13. Använd operatorn + med komplexa tal. Denna rad lägger till den reella delen av ett tal till den reella delen av ett annat tal.
  14. Använd operatorn + med komplexa tal. Denna linje kommer att lägga till den imaginära delen av ett tal till den imaginära delen av ett annat tal.
  15. Programmet kommer att returnera värdet på variabelresultatet vid framgångsrik exekvering.
  16. Slutet på definitionen av den nya betydelsen av + operatör, det vill säga överbelastning.
  17. Anropa metoden print().
  18. Skriv ut det nya komplexa numret efter tillägg på konsolen.
  19. Slutet på body of print()-funktionen.
  20. Slutet på brödtexten i klassen ComplexNum.
  21. Anropa main()-funktionen.
  22. Godkänn värdena för både verkliga och komplexa delar som ska läggas till. Den första delen av c1 kommer att läggas till den första delen av c2, det vill säga 10+3. Den andra delen av c1 kommer att läggas till den andra delen av c, det vill säga 2+7.
  23. Utför en operation med operatorn överbelastad + och lagra resultatet i variabel c3.
  24. Skriv ut värdet för variabel c3 på konsolen.
  25. Slutet på huvuddelen av funktionen main().

Runtime polymorfism

Detta händer när ett objekts metod anropas/anropas under körning snarare än under kompileringstid. Runtime polymorfism uppnås genom funktionsöverstyrning. Funktionen som ska anropas/anropas etableras under körning.

Funktion Åsidosättande

Funktionsöverstyrning inträffar när en funktion av basklassen ges en ny definition i en härledd klass. Vid den tiden kan vi säga att basfunktionen har åsidosatts.

Till exempel:

#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;

}

Produktion:

Funktion Åsidosättande

Här är en skärmdump av koden:

Funktion Åsidosättande

Kodförklaring:

  1. Importera iostream-huvudfilen till vårt program för att använda dess funktioner.
  2. Inkludera std-namnområdet i vårt program för att kunna använda dess klasser utan att anropa det.
  3. Skapa en klass som heter Mammal. { markerar början av klasskroppen.
  4. Använd public access-modifieraren för att ställa in funktionen vi ska skapa som allmänt tillgänglig. Den kommer att vara tillgänglig utanför denna klass.
  5. Skapa en offentlig funktion som heter eat. { markerar början av funktionskroppen.
  6. Skriv ut satsen som läggs till cout-funktionen när funktionen eat() anropas.
  7. I slutet av kroppen av funktion eat().
  8. Slutet av kroppen av klassen däggdjur.
  9. Skapa en klass som heter Ko som ärver klassen däggdjur. Ko är den härledda klassen, medan däggdjur är basklassen. { markerar början på denna klass.
  10. Använd public access-modifieraren för att markera funktionen vi håller på att skapa som allmänt tillgänglig. Den kommer att vara tillgänglig utanför denna klass.
  11. Åsidosätt funktionen eat() som definierades i basklassen. { markerar början av funktionskroppen.
  12. Uttalandet som ska skrivas ut på konsolen när denna funktion anropas.
  13. Slutet av kroppen av funktionen eat().
  14. Slutet av kroppen av klassen Ko.
  15. Anropa main()-funktionen. { markerar början på kroppen av denna funktion.
  16. Skapa en instans av Cow-klassen och ge den namnet c.
  17. Anropa eat()-funktionen definierad i Cow-klassen.
  18. Programmet måste returnera ett värde efter framgångsrikt slutförande.
  19. Slutet på main()-funktionen.

C++ Virtuell funktion

En virtuell funktion är ett annat sätt att implementera runtime polymorfism i C++. Det är en speciell funktion som definieras i en basklass och omdefinieras i den härledda klassen. För att deklarera en virtuell funktion bör du använda det virtuella nyckelordet. Nyckelordet ska föregå deklarationen av funktionen i basklassen.

Om en virtuell funktionsklass ärvs, omdefinierar den virtuella funktionen den virtuella funktionen för att passa dess behov. Till exempel:

#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();      
	}

Produktion:

C++ Virtuell funktion

Här är en skärmdump av koden:

C++ Virtuell funktion

Kodförklaring:

  1. Inkludera iostream-huvudfilen i koden för att använda dess funktioner.
  2. Inkludera std-namnområdet i vår kod för att använda dess klasser utan att anropa det.
  3. Skapa en klass som heter ClassA.
  4. Använd public access modifier för att markera en klassmedlem som allmänt tillgänglig.
  5. Skapa en virtuell funktion som heter show(). Det blir en offentlig funktion.
  6. Texten som ska skrivas ut när show() anropas anropas. Slutet är en C++ nyckelord, vilket betyder slutrad. Den flyttar muspekaren till nästa rad.
  7. Slutet på kroppen av den virtuella funktionen show().
  8. Slutet på kroppen av klassen Klass A.
  9. Skapar en ny klass med namnet ClassB som ärver klassen ClassA. KlassA blir basklassen medan KlassB blir den härledda klassen.
  10. Använd public access modifier för att markera en klassmedlem som allmänt tillgänglig.
  11. Omdefiniera den virtuella funktionen show() som härleds i basklassen.
  12. Texten som ska skrivas ut på konsolen när show()-funktionen definierad i den härledda klassen anropas.
  13. Slutet på brödtexten för funktionen show().
  14. Slutet på kroppen av den härledda klassen, klass B.
  15. Anropa main()-funktionen. Programlogiken bör läggas till i dess kropp.
  16. Skapa en pekarvariabel med namnet a. Den pekar på klassen som heter ClassA.
  17. Skapa en instans av klassen med namnet ClassB. Förekomsten får namnet b.
  18. Tilldela värdena lagras i adressen b i variabeln a.
  19. Anropa show()-funktionen definierad i den härledda klassen. Sen bindning har genomförts.
  20. Slutet på huvuddelen av funktionen main().

Kompileringstidspolymorfism vs. Run-Time Polymorphism

Här är de stora skillnaderna mellan de två:

Kompileringstid polymorfism Run-time polymorfism
Det kallas också tidig bindning eller statisk polymorfism Det kallas också sen/dynamisk bindning eller dynamisk polymorfism
Metoden anropas/anropas under kompileringstiden Metoden anropas/anropas under körning
Implementeras via funktionsöverbelastning och operatörsöverbelastning Implementeras via metodöverstyrning och virtuella funktioner
Exempel, metodöverbelastning. Många metoder kan ha liknande namn men olika antal eller typer av argument Exempel, överordnad metod. Många metoder kan ha ett liknande namn och samma prototyp.
Snabbare exekvering eftersom metodupptäckten görs under kompileringstiden Långsammare exekvering eftersom metodupptäckare görs under körning.
Less flexibilitet för problemlösning tillhandahålls eftersom allt är känt under kompileringstiden. Mycket flexibilitet tillhandahålls för att lösa komplexa problem eftersom metoder upptäcks under körning.

Sammanfattning

  • Polymorfism betyder att ha många former.
  • Det uppstår när det finns en hierarki av klasser som är relaterade genom arv.
  • Med polymorfism kan en funktion bete sig annorlunda baserat på objektet som anropar/kallar den.
  • I kompileringstidspolymorfism etableras funktionen som ska anropas under kompileringstiden.
  • I körtidspolymorfism etableras funktionen som ska anropas under körning.
  • Kompileringstidspolymorfism bestäms genom funktionsöverbelastning och operatörsöverbelastning.
  • Vid funktionsöverbelastning finns det många funktioner med liknande namn men olika argument.
  • Parametrarna kan skilja sig åt i antal eller typ.
  • Vid operatörsöverbelastning definieras en ny betydelse för C++ operatörer.
  • Runtime polymorfism uppnås genom funktionsöverstyrning.
  • Vid funktionsöverstyrning ger en härledd klass en ny definition till en funktion definierad i basklassen.