C++ Polimorfismo con esempio
In cosa consiste il polimorfismo C++?
In C++, il polimorfismo fa sì che una funzione membro si comporti diversamente in base all'oggetto che la chiama/invoca. Polimorfismo è una parola greca che significa avere molte forme. Si verifica quando si dispone di una gerarchia di classi correlate tramite ereditarietà.
Ad esempio, supponiamo di avere la funzione makeSound(). Quando un gatto richiama questa funzione, produrrà il suono miagolio. Quando una mucca richiama la stessa funzione, emetterà il suono del muggito.
Sebbene abbiamo una funzione, questa si comporta diversamente in circostanze diverse. La funzione ha molte forme; quindi, abbiamo raggiunto il polimorfismo.
Tipi di polimorfismo
C++ supporta due tipi di polimorfismo:
- Polimorfismo in fase di compilazione e
- Polimorfismo di runtime.
Polimorfismo in fase di compilazione
Si richiamano le funzioni sovraccaricate facendo corrispondere il numero e il tipo di argomenti. Le informazioni sono presenti durante la compilazione. Ciò significa che C++ il compilatore selezionerà la funzione giusta in fase di compilazione.
Il polimorfismo in fase di compilazione si ottiene tramite l'overloading delle funzioni e l'overloading degli operatori.
Sovraccarico delle funzioni
Il sovraccarico delle funzioni si verifica quando abbiamo molte funzioni con nomi simili ma argomenti diversi. Gli argomenti possono differire in termini di numero o tipo.
esempio 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; }
Produzione:
Ecco uno screenshot del codice:
Spiegazione del codice:
- Includi il file di intestazione iostream nel nostro codice. Potremo utilizzare le sue funzioni.
- Includi lo spazio dei nomi std nel nostro codice. Potremo utilizzare le sue classi senza chiamarlo.
- Crea una funzione denominata test che accetta un parametro intero i. Il { segna l'inizio del corpo del test funzionale.
- Istruzione da eseguire se viene invocato/chiamato il test funzionale di cui sopra.
- Fine del corpo del test funzionale di cui sopra.
- Crea una funzione denominata test che accetta un parametro float f. Il { segna l'inizio del corpo del test funzionale.
- Istruzione da eseguire se viene invocato/chiamato il test funzionale di cui sopra.
- Fine del corpo del test funzionale di cui sopra.
- Crea una funzione denominata test che accetta un parametro di carattere ch. Il { segna l'inizio del corpo del test funzionale.
- Istruzione da eseguire se viene invocato/chiamato il test funzionale di cui sopra.
- Fine del corpo del test funzionale di cui sopra.
- Chiama la funzione main(). Il { segna l'inizio del corpo della funzione.
- Chiama la funzione test e passale 5 come valore dell'argomento. Ciò richiama la funzione di test che accetta un argomento intero, ovvero la prima funzione di test.
- Chiama la funzione test e passale 5.5 come valore dell'argomento. Ciò invocherà la funzione di test che accetta un argomento float, ovvero la seconda funzione di test.
- Chiama la funzione test e passale cinque come valore dell'argomento. Ciò invocherà la funzione di test che accetta un argomento di tipo carattere, ovvero la terza funzione di test.
- Il programma deve restituire un valore se viene eseguito correttamente.
- La fine del corpo della funzione main().
Abbiamo tre funzioni con lo stesso nome ma diversi tipi di argomenti. Abbiamo raggiunto il polimorfismo.
Operasovraccarico
In Operato Overloading, definiamo un nuovo significato per a C++ operatore. Cambia anche il modo in cui funziona l'operatore. Ad esempio, possiamo definire l'operatore + per concatenare due stringhe. Lo conosciamo come operatore di addizione per aggiungere valori numerici. Dopo la nostra definizione, quando viene inserito tra interi, li aggiungerà. Quando viene inserito tra stringhe, le concatenerà.
esempio 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(); }
Produzione:
Ecco uno screenshot del codice:
Spiegazione del codice:
- Includi il file header iostream nel nostro programma per poter utilizzare le sue funzioni.
- Includi lo spazio dei nomi std nel nostro programma per poter utilizzare le sue classi senza chiamarlo.
- Crea una classe denominata ComplexNum. { segna l'inizio del corpo della classe.
- Utilizza il modificatore di accesso privato per contrassegnare le variabili come private, il che significa che è possibile accedervi solo dall'interno della classe.
- Definire due variabili intere, reale e superiore.
- Utilizza il modificatore di accesso pubblico per contrassegnare il costruttore come pubblico, il che significa che sarà accessibile anche dall'esterno classe.
- Creare il costruttore della classe e inizializzare le variabili.
- Inizializza il valore della variabile real.
- Inizializza il valore della variabile sopra.
- Fine del corpo del costruttore.
- Dobbiamo sovrascrivere il significato dell'operatore +.
- Crea il risultato del tipo di dati ComplexNum.
- Usa l'operatore + con numeri complessi. Questa riga aggiungerà la parte reale di un numero alla parte reale di un altro numero.
- Usa l'operatore + con numeri complessi. Questa riga aggiungerà la parte immaginaria di un numero alla parte immaginaria di un altro numero.
- Il programma restituirà il valore della variabile result dopo l'esecuzione riuscita.
- Fine della definizione del nuovo significato dell'operatore +, cioè sovraccarico.
- Chiama il metodo print().
- Stampa il nuovo numero complesso dopo l'addizione sulla console.
- Fine del corpo della funzione print().
- Fine del corpo della classe ComplexNum.
- Chiama la funzione main().
- Passare i valori delle parti reali e complesse da sommare. La prima parte di c1 verrà sommata alla prima parte di c2, ovvero 10+3. La seconda parte di c1 verrà sommata alla seconda parte di c, ovvero 2+7.
- Eseguire un'operazione utilizzando l'operatore sovraccaricato + e memorizzando il risultato nella variabile c3.
- Stampa il valore della variabile c3 sulla console.
- Fine del corpo della funzione main().
Polimorfismo di runtime
Ciò accade quando il metodo di un oggetto viene invocato/chiamato durante il runtime anziché durante la compilazione. Il polimorfismo di runtime si ottiene tramite l'override delle funzioni. La funzione da chiamare/invocare viene stabilita in fase di runtime.
Sovrascrittura delle funzioni
L'override della funzione si verifica quando a una funzione della classe base viene assegnata una nuova definizione in una classe derivata. A quel punto, possiamo dire che la funzione di base è stata sovrascritta.
Per esempio:
#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; }
Produzione:
Ecco uno screenshot del codice:
Spiegazione del codice:
- Importa il file header iostream nel nostro programma per utilizzare le sue funzioni.
- Includi lo spazio dei nomi std nel nostro programma per poter utilizzare le sue classi senza chiamarlo.
- Crea una classe chiamata Mammifero. Il { segna l'inizio del corpo della classe.
- Utilizza il modificatore di accesso pubblico per impostare la funzione che stiamo per creare come accessibile pubblicamente. Sarà accessibile dall'esterno di questa classe.
- Crea una funzione pubblica denominata mangia. Il { segna l'inizio del corpo della funzione.
- Stampa l'istruzione aggiunta alla funzione cout quando viene invocata la funzione eat().
- La fine del corpo della funzione eat().
- Fine del corpo della classe Mammifero.
- Crea una classe denominata Mucca che eredita la classe Mammifero. La mucca è la classe derivata, mentre il mammifero è la classe base. Il { segna l'inizio di questa lezione.
- Utilizza il modificatore di accesso pubblico per contrassegnare la funzione che stiamo per creare come accessibile pubblicamente. Sarà accessibile dall'esterno di questa classe.
- Sostituisci la funzione eat() definita nella classe base. Il { segna l'inizio del corpo della funzione.
- L'istruzione da stampare sulla console quando viene richiamata questa funzione.
- Fine del corpo della funzione eat().
- Fine del corpo della classe Mucca.
- Chiama la funzione main(). Il { segna l'inizio del corpo di questa funzione.
- Creare un'istanza della classe Cow e darle il nome c.
- Chiama la funzione eat() definita nella classe Cow.
- Il programma deve restituire un valore in caso di completamento positivo.
- Fine della funzione main().
C++ Funzione virtuale
Una funzione virtuale è un altro modo di implementare il polimorfismo in fase di esecuzione C++. È una funzione speciale definita in una classe base e ridefinita nella classe derivata. Per dichiarare una funzione virtuale, dovresti usare la parola chiave virtual. La parola chiave dovrebbe precedere la dichiarazione della funzione nella classe base.
Se una classe di funzione virtuale viene ereditata, la classe virtuale ridefinisce la funzione virtuale per adattarla alle proprie esigenze. Per esempio:
#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(); }
Produzione:
Ecco uno screenshot del codice:
Spiegazione del codice:
- Includere il file di intestazione iostream nel codice per utilizzare le sue funzioni.
- Includi lo spazio dei nomi std nel nostro codice per utilizzare le sue classi senza chiamarlo.
- Crea una classe denominata ClassA.
- Utilizza il modificatore di accesso pubblico per contrassegnare un membro della classe come accessibile pubblicamente.
- Crea una funzione virtuale denominata show(). Sarà una funzione pubblica.
- Il testo da stampare quando viene invocato show(). La fine è a C++ parola chiave, che significa riga di fine. Sposta il cursore del mouse sulla riga successiva.
- Fine del corpo della funzione virtuale show().
- Fine del corpo della classe ClassA.
- Creazione di una nuova classe denominata ClassB che eredita la classe ClassA. ClassA diventa la classe base mentre ClassB diventa la classe derivata.
- Utilizza il modificatore di accesso pubblico per contrassegnare un membro della classe come accessibile pubblicamente.
- Ridefinire la funzione virtuale show() derivata nella classe base.
- Il testo da stampare sulla console quando viene richiamata la funzione show() definita nella classe derivata.
- Fine del corpo della funzione show().
- Fine del corpo della classe derivata, ClassB.
- Chiama la funzione main(). La logica del programma dovrebbe essere aggiunta all'interno del suo corpo.
- Creare una variabile puntatore denominata a. Punta alla classe denominata ClassA.
- Crea un'istanza della classe denominata ClassB. All'istanza viene assegnato il nome b.
- Assegnare i valori memorizzati nell'indirizzo b nella variabile a.
- Richiama la funzione show() definita nella classe derivata. È stata implementata la rilegatura tardiva.
- Fine del corpo della funzione main().
Polimorfismo in fase di compilazione vs. Polimorfismo in fase di esecuzione
Ecco le principali differenze tra i due:
Polimorfismo in fase di compilazione | Polimorfismo run-time |
---|---|
Si chiama anche polimorfismo di legame precoce o statico | È chiamato anche legame tardivo/dinamico o polimorfismo dinamico |
Il metodo viene chiamato/invocato durante la fase di compilazione | Il metodo viene chiamato/invocato durante il runtime |
Implementato tramite l'overload delle funzioni e l'overload degli operatori | Implementato tramite override del metodo e funzioni virtuali |
Esempio, sovraccarico del metodo. Molti metodi possono avere nomi simili ma numero o tipi di argomenti diversi | Esempio, override del metodo. Molti metodi possono avere un nome simile e lo stesso prototipo. |
Esecuzione più rapida poiché il rilevamento dei metodi viene eseguito durante la fase di compilazione | Esecuzione più lenta poiché il rilevamento dei metodi viene eseguito durante il runtime. |
Less viene fornita flessibilità per la risoluzione dei problemi poiché tutto è noto durante la fase di compilazione. | Viene garantita una grande flessibilità nella risoluzione di problemi complessi poiché i metodi vengono scoperti durante l'esecuzione. |
Sintesi
- Polimorfismo significa avere molte forme.
- Si verifica quando esiste una gerarchia di classi correlate tramite ereditarietà.
- Con il polimorfismo una funzione può comportarsi diversamente in base all'oggetto che la invoca/chiama.
- Nel polimorfismo in fase di compilazione, la funzione da invocare viene stabilita durante la fase di compilazione.
- Nel polimorfismo runtime, la funzione da invocare viene stabilita durante il runtime.
- Il polimorfismo in fase di compilazione viene determinato tramite l'overload delle funzioni e l'overload degli operatori.
- Nell'overloading delle funzioni, esistono molte funzioni con nomi simili ma argomenti diversi.
- I parametri possono differire per numero o tipologia.
- Nell'overloading degli operatori viene definito un nuovo significato per C++ Operatori.
- Il polimorfismo di runtime si ottiene tramite l'override delle funzioni.
- Nell'override di una funzione, una classe derivata fornisce una nuova definizione a una funzione definita nella classe base.