polymorphism c
Rolul polimorfismului în C ++ cu exemple.
Polimorfismul este unul dintre cei patru piloni ai programării orientate pe obiecte. Polimorfismul înseamnă a avea multe forme. Poate fi definit ca tehnica prin care un obiect poate lua mai multe forme în funcție de situație.
În termeni de programare, putem spune că un obiect se poate comporta diferit în condiții diferite.
În acest tutorial, vom afla despre tipurile de polimorfism, modalitățile de implementare a polimorfismului împreună cu diferitele alte concepte ale polimorfismului în detaliu.
=> Verificați aici pentru a vedea A-Z a tutorialelor de formare C ++ aici.
De exemplu, o femeie poate lua multe roluri în diferite situații. Pentru un copil, ea este mamă, casnică acasă, lucrătoare la birou etc. Deci, o femeie își asumă roluri diferite și prezintă un comportament diferit în diferite condiții. Acesta este un exemplu real de polimorfism.
În mod similar și în lumea programării, putem avea un operator „+” care este operatorul de adunare binară care se comportă diferit atunci când operanzii se schimbă. De exemplu, atunci când ambii operanzi sunt numerici, efectuează adunare.
Pe de altă parte, când operanzii sunt șiruri, acționează ca operator de concatenare. Astfel, polimorfismul, pe scurt, înseamnă o entitate care ia multe forme sau se comportă diferit în condiții diferite.
Ce veți învăța:
- Tipuri de polimorfism
- Compilați timp polimorfism vs. Polimorfism în timp de execuție
- Compilați polimorfismul în timp
- Funcția de supraîncărcare
- Supraîncărcarea operatorului
- Concluzie
- Lectură recomandată
Tipuri de polimorfism
Polimorfismul este împărțit în două tipuri.
- Compilați polimorfismul în timp
- Polimorfismul în timpul rulării
Diagrama care reprezintă acest lucru este prezentată mai jos:
Așa cum se arată în diagrama de mai sus, polimorfismul este împărțit în polimorfism în timp de compilare și polimorfism în timpul rulării. Polimorfismul de timp de compilare este împărțit în continuare în supraîncărcarea operatorului și supraîncărcarea funcției. Polimorfismul de rulare este implementat în continuare folosind funcții virtuale.
Compilarea timp polimorfism este, de asemenea, cunoscut sub numele de legare timpurie sau polimorfism static. În acest tip de polimorfism, metoda obiectului este invocată la momentul compilării. În cazul polimorfismului în timpul rulării, metoda obiectului este invocată în timpul rulării.
Polimorfismul în timpul rulării este, de asemenea, cunoscut sub numele de legare dinamică sau tardivă sau polimorfism dinamic. Vom analiza implementarea detaliată a fiecăreia dintre aceste tehnici în următoarele subiecte.
Compilați timp polimorfism vs. Polimorfism în timp de execuție
Să vedem principalele diferențe dintre timpul de compilare și polimorfismul de rulare de mai jos.
Compilați polimorfismul în timp | Polimorfismul în timpul rulării |
---|---|
De asemenea, cunoscut sub numele de polimorfism static sau legare timpurie | De asemenea, cunoscut sub numele de polimorfism dinamic sau legare tardivă / dinamică |
Metoda obiectelor este invocată la compilare | Metoda obiectului este invocată în timpul rulării |
De obicei implementat folosind supraîncărcarea operatorului și supraîncărcarea funcției | Implementat folosind funcții virtuale și suprascrierea metodei |
Supraîncărcarea metodei este un polimorfism de compilare în care mai multe metode pot avea același nume, dar listă de parametri și tipuri diferite. | Anularea metodei este polimorfismul în timpul rulării în care mai multe metode au același nume cu același prototip |
Deoarece metodele sunt cunoscute la momentul compilării, execuția este mai rapidă | Executarea este mai lentă, deoarece metoda este cunoscută în timpul rulării |
Oferiți mai puțină flexibilitate pentru implementarea soluțiilor, deoarece totul trebuie să fie cunoscut la compilare | Mult mai flexibil pentru implementarea soluțiilor complexe, deoarece metodele sunt decise în timpul rulării |
Compilați polimorfismul în timp
Polimorfismul de timp de compilare este o tehnică în care metoda unui obiect este invocată la timpul de compilare.
Acest tip de polimorfism este implementat în două moduri.
- Supraîncărcarea funcției
- Suprasolicitarea operatorului
Vom discuta fiecare tehnică în detaliu.
Funcția de supraîncărcare
Se spune că o funcție este supraîncărcată atunci când avem mai multe funcții cu același nume, dar tipuri diferite de parametri sau un număr diferit de argumente.
Astfel, o funcție poate fi supraîncărcată pe baza tipurilor de parametri, ordinea parametrilor și numărul de parametri.
Rețineți că două funcții având același nume și aceeași listă de parametri, dar un tip de returnare diferit nu este o funcție supraîncărcată și va avea ca rezultat o eroare de compilare dacă este utilizată în program.
În mod similar, atunci când parametrii funcției diferă doar în indicator și dacă tipul de matrice este echivalent, atunci nu ar trebui să fie utilizat pentru supraîncărcare.
Alte tipuri, cum ar fi statice și nestatice, const și volatile, etc. Sau declarațiile de parametri care diferă în prezența sau absența valorilor implicite nu trebuie, de asemenea, utilizate pentru supraîncărcare, deoarece sunt echivalente din punctul de vedere al implementării.
De exemplu,următoarele prototipuri de funcții sunt funcții supraîncărcate.
Add(int,int); Add(int,float); Add(float,int); Add(int,int,int);
În prototipurile de mai sus, vedem că suprasolicităm funcția Adăugare în funcție de tipul de parametri, secvența sau ordinea parametrilor, numărul de parametri etc.
Să luăm un exemplu complet de programare pentru a înțelege mai bine funcția de supraîncărcare.
#include #include using namespace std; class Summation { public: int Add(int num1,int num2) { return num1+num2; } int Add(int num1,int num2, int num3) { return num1+num2+num3; } string Add(string s1,string s2){ return s1+s2; } }; int main(void) { Summation obj; cout< Ieșire:
35
191
19
Salut Lume
În programul de mai sus, avem o clasă Summation care a definit trei funcții supraîncărcate numite Adăugare care ia două argumente întregi, trei argumente întregi și două argumente șir.
În funcția principală, efectuăm patru apeluri funcționale care furnizează diverși parametri. Primele două apeluri funcționale sunt simple. În cel de-al treilea apel funcțional la Adăugare, oferim două valori în virgulă mobilă ca argumente.
În acest caz, funcția care este potrivită este int Adăugare (int, int) ca intern, float-ul este convertit în dublu și apoi corelat cu funcția cu parametrii int. Dacă am fi specificat double în loc de float, atunci am avea o altă funcție supraîncărcată cu double ca parametri.
Ultimul apel funcțional folosește valori de șir ca parametri. În acest caz, operatorul Add (+) acționează ca un operator de concatenare și concatenează cele două valori ale șirului pentru a produce un singur șir.
Avantajele supraîncărcării funcției
Principalul beneficiu al supraîncărcării funcției este că promovează reutilizarea codului. Putem avea cât mai multe funcții cu același nume cu condiția ca acestea să fie supraîncărcate pe baza tipului de argument, a secvenței de argument și a numărului de argumente.
Făcând acest lucru devine mai ușor să aveți funcții diferite cu același nume pentru a reprezenta comportamentul aceleiași operații în condiții diferite.
Dacă supraîncărcarea funcției nu era prezentă, atunci ar fi trebuit să scriem prea multe tipuri diferite de funcții cu nume diferite, făcând astfel codul ilizibil și dificil de adaptat.
Supraîncărcarea operatorului
Supraîncărcarea operatorului este tehnica prin care dăm o semnificație diferită operatorilor existenți în C ++. Cu alte cuvinte, supraîncărcăm operatorii pentru a da o semnificație specială tipurilor de date definite de utilizator ca obiecte.
Majoritatea operatorilor din C ++ sunt supraîncărcați sau au o semnificație specială, astfel încât să poată lucra pe tipuri de date definite de utilizator. Rețineți că, în timpul supraîncărcării, funcționarea de bază a operatorilor nu este modificată. Supraîncărcarea oferă operatorului o semnificație suplimentară, păstrându-și semantica de bază la fel.
Deși majoritatea operatorilor pot fi supraîncărcați în C ++, există unii operatori care nu pot fi supraîncărcați.
Acești operatori sunt enumerați în tabelul de mai jos.
Operatori Operator rezoluție domeniu (: :) Mărimea selector de membri (.) selector pointer membru (*) operator ternar (? :)
Funcțiile pe care le folosim pentru a supraîncărca operatorii se numesc „ Funcțiile operatorului ”.
Funcțiile operatorului sunt similare cu funcțiile normale, dar cu o diferență. Diferența este că numele funcțiilor operatorului începe cu cuvântul cheie „ operator ”Urmat de simbolul operatorului care urmează să fie supraîncărcat.
Funcția operator este apoi apelată atunci când operatorul corespunzător este utilizat în program. Aceste funcții de operator pot fi funcții membre sau metode globale sau chiar o funcție de prietenie.
Sintaxa generală a funcției operator este:
return_type classname::operator op(parameter list) { //function body }
Aici „operator op” este funcția operator în care operatorul este cuvântul cheie și op este operatorul care trebuie supraîncărcat. Return_type este tipul de valoare care trebuie returnat.
Să vedem câteva exemple de programare pentru a demonstra supraîncărcarea operatorului folosind funcțiile operatorului.
Exemplul 1:Supraîncărcarea operatorului unar folosind funcția de operator membru.
#include using namespace std; class Distance { public: int feet; // Constructor to initialize the object's value Distance(int feet) { this->feet = feet; } //operator function to overload ++ operator to perform increment on Distance obj void operator++() { feet++; } void print(){ cout << '
Incremented Feet value: ' << feet; } }; int main() { Distance d1(9); // Use (++) unary operator ++d1; d1.print(); return 0; }
Ieșire:
Valoare picioare mărite: 10
Aici am supraîncărcat operatorul de incrementare unitar folosind funcția operator ++. În funcția principală, folosim acest operator ++ pentru a incrementa obiectul clasei Distanță.
Exemplul 2:Supraîncărcarea operatorului binar utilizând funcția de operator membru.
#include using namespace std; class Complex { int real, imag; public: Complex(int r = 0, int i =0) {real = r; imag = i;} //Operator function to overload binary + to add two complex numbers Complex operator + (Complex const &obj) { Complex c3; c3.real = real + obj.real; c3.imag = imag + obj.imag; return c3; } void print() { cout << real << ' + i' << imag << endl; } }; int main() { Complex c1(2, 5), c2(3, 7); cout<<'c1 = '; c1.print(); cout<<'c2 = '; c2.print(); cout<<'c3 = c1+c2 = '; Complex c3 = c1 + c2; // calls overloaded + operator c3.print(); }
Ieșire:
c1 = 2 + i5
c2 = 3 + i7
c3 = c1 + c2 = 5 + i12
Aici am folosit exemplul clasic al adăugării a două numere complexe folosind supraîncărcarea operatorului. Definim o clasă pentru a reprezenta numere complexe și o funcție de operator pentru supraîncărcare + operator în care adăugăm părțile reale și imaginare ale numerelor complexe.
În funcția principală, declarăm două obiecte complexe și le adăugăm folosind operatorul supraîncărcat + pentru a obține rezultatul dorit.
În exemplul de mai jos, vom folosi funcția prieten pentru a adăuga două numere complexe pentru a vedea diferența în implementare.
#include using namespace std; class Complex { int real, imag; public: Complex(int r = 0, int i =0) {real = r; imag = i;} //friend function to overload binary + to add two complex numbers friend Complex operator +(Complex const &, Complex const &); void print() { cout << real << ' + i' << imag << endl; } }; Complex operator + (Complex const &c1, Complex const &c2) { Complex c3; c3.real = c1.real + c2.real; c3.imag = c1.imag + c2.imag; return c3; } int main() { Complex c1(2, 5), c2(3, 7); cout<<'c1 = '; c1.print(); cout<<'c2 = '; c2.print(); cout<<'c3 = c1+c2 = '; Complex c3 = c1 + c2; // calls overloaded + operator c3.print(); }
Ieșire:
c1 = 2 + i5
c2 = 3 + i7
c3 = c1 + c2 = 5 + i12
Vedem că rezultatul programului este același. Singura diferență în implementare este utilizarea funcției prieten pentru a supraîncărca operatorul + în loc de o funcție membru în implementarea anterioară.
Când funcția prieten este utilizată pentru un operator binar, trebuie să specificăm în mod explicit ambii operanzi la funcție. În mod similar, atunci când operatorul unar este supraîncărcat folosind funcția prieten, trebuie să furnizăm un singur operand funcției.
În afară de funcțiile operatorului, putem scrie și un operator de conversie care este folosit pentru a converti de la un tip la altul. Acești operatori de conversie supraîncărcați ar trebui să fie o funcție membru a clasei.
modul de a face față anumitor situații
Exemplul 3:Suprasolicitarea operatorului folosind operatorul de conversie.
#include using namespace std; class DecFraction { int numerator, denom; public: DecFraction(int num, int denm) { numerator = num; denom = denm; } // conversion operator: converts fraction to float value and returns it operator float() const { return float(numerator) / float(denom); } }; int main() { DecFraction df(3, 5); //object of class float res_val = df; //calls conversion operator cout << 'The resultant value of given fraction (3,5)= '< Ieșire:
Valoarea rezultată a fracției date (3,5) = 0,6
În acest program, am folosit operatorul de conversie pentru a converti fracția dată într-o valoare float. După efectuarea conversiei, operatorul de conversie returnează apelantului valoarea rezultată.
În funcția principală, când atribuim obiectul df unei variabile res_val, conversia are loc și rezultatul este stocat în res_val.
De asemenea, putem apela un constructor cu un singur argument. Când putem apela un constructor din clasă folosind un singur argument, acesta se numește „ conversie constructor ”. Constructorul de conversie poate fi folosit pentru conversia implicită la clasa care se construiește.
#include using namespace std; class Point { private: int x,y; public: Point(int i=0,int j=0) {x = i;y=j;} void print() { cout<<' x = '< Ieșire:
Punct construit folosind un constructor normal
x = 20 y = 30
Punct construit folosind constructorul de conversie
x = 10 y = 0

Aici avem o clasă Point care definește un constructor cu valori implicite. În funcția principală, construim un obiect pt cu coordonatele x și y. Apoi, doar atribuim pt o valoare de 10. Aici se numește constructorul de conversie și x i se atribuie o valoare de 10, în timp ce lui i se dă valoarea implicită 0.
Reguli de supraîncărcare a operatorului
În timp ce efectuăm supraîncărcarea operatorului, trebuie să urmărim regulile de mai jos.
- În C ++, putem supraîncărca numai operatorii existenți. Operatorii nou adăugați nu pot fi supraîncărcați.
- Atunci când operatorii sunt supraîncărcați, trebuie să ne asigurăm că cel puțin unul dintre operanzi este de tipul definit de utilizator.
- Pentru a supraîncărca anumiți operatori, putem folosi și funcția prieten.
- Când supraîncărcăm operatorii unari folosind o funcție membru, aceasta nu ia niciun argument explicit. Este nevoie de un argument explicit atunci când operatorul unar este supraîncărcat folosind funcția prieten.
- În mod similar, atunci când operatorii binari sunt supraîncărcați folosind funcția membru, trebuie să oferim un argument explicit funcției. Când operatorii binari sunt supraîncărcați folosind funcția prieten, funcția ia două argumente.
- Există doi operatori în C ++ care sunt deja supraîncărcați. Acestea sunt „=” și „&”. Prin urmare, pentru a copia un obiect din aceeași clasă, nu trebuie să suprasolicităm operatorul = și îl putem folosi direct.
Avantajele supraîncărcării operatorului
Supraîncărcarea operatorului în C ++ ne permite să extindem funcționalitatea operatorilor la tipurile definite de utilizator, inclusiv obiecte de clasă, în plus față de tipurile încorporate.
Prin extinderea funcționalității operatorului la tipurile definite de utilizator, nu este necesar să scriem cod complex pentru a efectua diverse operații pe tipurile definite de utilizator, ci o putem face într-o singură operație la fel ca tipurile încorporate.
Concluzie
Polimorfismul de timp de compilare oferă facilități de supraîncărcare, în special pentru a extinde funcționalitatea codului în ceea ce privește supraîncărcarea funcției și supraîncărcarea operatorului.
Prin supraîncărcarea funcției, putem scrie mai multe funcții cu același nume, dar cu parametri și tipuri diferite. Acest lucru face codul simplu și ușor de citit. Prin supraîncărcarea operatorului, putem extinde funcționalitatea operatorilor, astfel încât să putem face operațiuni de bază și pe tipurile definite de utilizator.
În viitorul nostru tutorial, vom afla mai multe despre polimorfismul de rulare în C ++.
=> Citiți seria Easy C ++ Training.
Lectură recomandată
- Polimorfism în timp de execuție în C ++
- Funcții prieten în C ++
- Recursivitate în C ++
- Tutorial de funcții principale Python cu exemple practice
- O prezentare completă a C ++
- QTP Tutorial # 21 - Cum să faci testele QTP modulare și reutilizabile folosind acțiuni și biblioteci de funcții
- Tutorial Unix Pipes: Pipe în programarea Unix
- Funcții de bibliotecă în C ++