Cos'è il polimorfismo in C ++?
In C ++, il polimorfismo fa sì che una funzione membro si comporti in modo diverso in base all'oggetto che la chiama / invoca. Il polimorfismo è una parola greca che significa avere molte forme. Si verifica quando si dispone di una gerarchia di classi correlate tramite l'ereditarietà.
Ad esempio, supponiamo di avere la funzione makeSound (). Quando un gatto chiama questa funzione, produrrà il miagolio. Quando una mucca invoca la stessa funzione, fornirà il suono del muggito.
Sebbene abbiamo una funzione, si comporta in modo diverso in circostanze diverse. La funzione ha molte forme; quindi, abbiamo raggiunto il polimorfismo.
In questo tutorial C ++ imparerai:
- Cos'è il polimorfismo?
- Tipi di polimorfismo
- Compile Time Polymorphism
- Sovraccarico di funzioni
- Sovraccarico dell'operatore
- Polimorfismo di runtime
- Funzione di override
- Funzione virtuale C ++
- Polimorfismo in fase di compilazione vs. Polimorfismo di runtime
Tipi di polimorfismo
C ++ supporta due tipi di polimorfismo:
- Polimorfismo in fase di compilazione e
- Polimorfismo a runtime.
Compile Time Polymorphism
Si richiamano le funzioni sovraccaricate facendo corrispondere il numero e il tipo di argomenti. Le informazioni sono presenti durante la compilazione. Ciò significa che il compilatore C ++ selezionerà la funzione giusta in fase di compilazione.
Il polimorfismo in fase di compilazione si ottiene tramite il sovraccarico delle funzioni e il sovraccarico degli operatori.
Sovraccarico di 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:
#includeusing 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:
- Includere il file di intestazione iostream nel nostro codice. Potremo utilizzare le sue funzioni.
- Includere lo spazio dei nomi std nel nostro codice. Potremo usare le sue classi senza chiamarlo.
- Creare una funzione denominata test che accetta un parametro intero i. La {segna l'inizio del corpo del test funzionale.
- Istruzione da eseguire se viene invocato / chiamato il test della funzione precedente.
- Fine del corpo del test di funzionamento di cui sopra.
- Crea una funzione chiamata test che accetta un parametro float f. La {segna l'inizio del corpo del test funzionale.
- Istruzione da eseguire se viene invocato / chiamato il test della funzione precedente.
- Fine del corpo del test di funzionamento di cui sopra.
- Creare una funzione denominata test che accetta un parametro di carattere ch. La {segna l'inizio del corpo del test funzionale.
- Istruzione da eseguire se viene invocato / chiamato il test della funzione precedente.
- Fine del corpo del test di funzionamento di cui sopra.
- Chiama la funzione main (). La {segna l'inizio del corpo della funzione.
- Chiama la funzione test e passaci 5 come valore dell'argomento. Richiama la funzione di test che accetta un argomento intero, ovvero la prima funzione di test.
- Chiama la funzione test e passa ad essa 5.5 come valore dell'argomento. Questo richiamerà la funzione di test che accetta un argomento float, cioè la seconda funzione di test.
- Chiama la funzione test e passandole cinque come valore dell'argomento. Questo richiamerà la funzione di test che accetta un argomento carattere, cioè 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.
Sovraccarico dell'operatore
In Operator Overloading, definiamo un nuovo significato per un operatore C ++. Cambia anche il modo in cui lavora l'operatore. Ad esempio, possiamo definire l'operatore + per concatenare due stringhe. Lo conosciamo come l'operatore di addizione per l'aggiunta di valori numerici. Dopo la nostra definizione, se inserito tra numeri interi, li aggiungerà. Quando viene posizionato tra le stringhe, le concatenerà.
Esempio 2:
#includeusing 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:
- Includere il file di intestazione iostream nel nostro programma per poter utilizzare le sue funzioni.
- Includere lo spazio dei nomi std nel nostro programma per utilizzare le sue classi senza chiamarlo.
- Crea una classe denominata ComplexNum. La {segna l'inizio del corpo della classe.
- Utilizza il modificatore di accesso privato per contrassegnare le variabili come private, ovvero è possibile accedervi solo dall'interno della classe.
- Definisci due variabili intere, reale e superiore.
- Usa il modificatore di accesso pubblico per contrassegnare il costruttore come pubblico, il che significa che sarà accessibile anche dall'esterno della classe.
- Creare il costruttore della classe e inizializzare le variabili.
- Inizializza il valore della variabile real.
- Inizializza il valore della variabile su.
- Fine del corpo del costruttore.
- Dobbiamo sovrascrivere il significato dell'operatore +.
- Creare il risultato del tipo di dati di tipo ComplexNum.
- Utilizza l'operatore + con numeri complessi. Questa riga aggiungerà la parte reale di un numero alla parte reale di un altro numero.
- Utilizza l'operatore + con numeri complessi. Questa linea aggiungerà la parte immaginaria di un numero alla parte immaginaria di un altro numero.
- Il programma restituirà il valore del risultato della variabile in caso di corretta esecuzione.
- Fine della definizione del nuovo significato di operatore +, cioè sovraccarico.
- Chiama il metodo print ().
- Stampa il nuovo numero complesso dopo l'aggiunta sulla console.
- Fine del corpo della funzione print ().
- Fine del corpo della classe ComplexNum.
- Chiama la funzione main ().
- Passa i valori delle parti sia reali che complesse da aggiungere. La prima parte di c1 verrà aggiunta alla prima parte di c2, ovvero 10 + 3. La seconda parte di c1 verrà aggiunta alla seconda parte di c, ovvero 2 + 7.
- Eseguire un'operazione utilizzando l'operatore di overload + e archiviando 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 durante il runtime.
Funzione di override
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:
#includeusing 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 di intestazione iostream nel nostro programma per utilizzare le sue funzioni.
- Includere lo spazio dei nomi std nel nostro programma per utilizzare le sue classi senza chiamarlo.
- Crea una classe chiamata Mammal. La {segna l'inizio del corpo della classe.
- Usa 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 chiamata eat. La {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 Cow che eredita la classe Mammal. Cow è la classe derivata, mentre Mammal è la classe base. La {segna l'inizio di questa classe.
- Usa 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. La {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 (). La {segna l'inizio del corpo di questa funzione.
- Crea un'istanza della classe Cow e assegnandole il nome c.
- Chiama la funzione eat () definita nella classe Cow.
- Il programma deve restituire un valore dopo il completamento con successo.
- Fine della funzione main ().
Funzione virtuale C ++
Una funzione virtuale è un altro modo per implementare il polimorfismo di runtime in 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 in base alle proprie esigenze. Per esempio:
#includeusing 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.
- Includere 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 chiamata show (). Sarà una funzione pubblica.
- Il testo da stampare quando viene invocato show (). Endl è una parola chiave C ++, che significa end line. 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.
- Crea 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 l'associazione tardiva.
- Fine del corpo della funzione main ().
Polimorfismo in fase di compilazione vs. Polimorfismo di runtime
Ecco le principali differenze tra i due:
Polimorfismo in fase di compilazione | Polimorfismo run-time |
È anche chiamato polimorfismo di legame precoce o statico | È anche chiamato 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 sovraccarico delle funzioni e sovraccarico dell'operatore | 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, sostituzione del metodo. Molti metodi possono avere un nome simile e lo stesso prototipo. |
Esecuzione più rapida poiché la scoperta dei metodi viene eseguita durante la compilazione | Esecuzione più lenta poiché il rilevamento del metodo viene eseguito durante il runtime. |
Viene fornita una minore flessibilità per la risoluzione dei problemi poiché tutto è noto durante la fase di compilazione. | Viene fornita molta flessibilità per risolvere problemi complessi poiché i metodi vengono rilevati durante il runtime. |
Sommario:
- Il polimorfismo significa avere molte forme.
- Si verifica quando esiste una gerarchia di classi correlate tramite l'ereditarietà.
- Con il polimorfismo, una funzione può comportarsi in modo diverso in base all'oggetto che la invoca / la chiama.
- Nel polimorfismo in fase di compilazione, la funzione da invocare viene stabilita durante la fase di compilazione.
- Nel polimorfismo di runtime, la funzione da invocare viene stabilita durante il runtime.
- Il polimorfismo in fase di compilazione viene determinato tramite il sovraccarico delle funzioni e il sovraccarico degli operatori.
- Nel sovraccarico di funzioni, ci sono molte funzioni con nomi simili ma argomenti diversi.
- I parametri possono differire in numero o tipo.
- Nell'overloading degli operatori, viene definito un nuovo significato per gli operatori C ++.
- Il polimorfismo di runtime si ottiene tramite l'override delle funzioni.
- Nella sostituzione della funzione, una classe derivata fornisce una nuova definizione a una funzione definita nella classe base.