C++ Πολυμορφισμός με Παράδειγμα
Σε τι είναι ο Πολυμορφισμός C++?
In C++, ο πολυμορφισμός κάνει μια συνάρτηση μέλους να συμπεριφέρεται διαφορετικά με βάση το αντικείμενο που την καλεί/καλεί. Ο πολυμορφισμός είναι ελληνική λέξη που σημαίνει να έχεις πολλές μορφές. Εμφανίζεται όταν έχετε μια ιεραρχία κλάσεων που σχετίζονται μέσω κληρονομικότητας.
Για παράδειγμα, ας υποθέσουμε ότι έχουμε τη συνάρτηση makeSound(). Όταν μια γάτα καλεί αυτή τη λειτουργία, θα παράγει τον ήχο νιαουρίσματος. Όταν μια αγελάδα επικαλείται την ίδια λειτουργία, θα δώσει τον ήχο κούρασης.
Αν και έχουμε μία λειτουργία, αυτή συμπεριφέρεται διαφορετικά υπό διαφορετικές συνθήκες. Η συνάρτηση έχει πολλές μορφές. Ως εκ τούτου, έχουμε επιτύχει πολυμορφισμό.
Τύποι πολυμορφισμού
C++ υποστηρίζει δύο τύπους πολυμορφισμού:
- Πολυμορφισμός χρόνου μεταγλώττισης, και
- Πολυμορφισμός χρόνου εκτέλεσης.
Σύνταξη Χρονικού Πολυμορφισμού
Επικαλείτε τις υπερφορτωμένες συναρτήσεις ταιριάζοντας τον αριθμό και τον τύπο των ορισμάτων. Οι πληροφορίες είναι παρούσες κατά τη διάρκεια του χρόνου μεταγλώττισης. Αυτό σημαίνει το C++ ο μεταγλωττιστής θα επιλέξει τη σωστή λειτουργία κατά τη στιγμή της μεταγλώττισης.
Ο πολυμορφισμός χρόνου μεταγλώττισης επιτυγχάνεται μέσω υπερφόρτωσης συναρτήσεων και υπερφόρτωσης χειριστή.
Λειτουργία Υπερφόρτωση
Η υπερφόρτωση συναρτήσεων συμβαίνει όταν έχουμε πολλές συναρτήσεις με παρόμοια ονόματα αλλά διαφορετικά ορίσματα. Τα ορίσματα μπορεί να διαφέρουν ως προς τον αριθμό ή τον τύπο.
Παράδειγμα 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; }
Παραγωγή:
Εδώ είναι ένα στιγμιότυπο οθόνης του κώδικα:
Επεξήγηση κώδικα:
- Συμπεριλάβετε το αρχείο κεφαλίδας iostream στον κώδικά μας. Θα μπορούμε να χρησιμοποιήσουμε τις λειτουργίες του.
- Συμπεριλάβετε τον χώρο ονομάτων std στον κώδικά μας. Θα μπορούμε να χρησιμοποιήσουμε τις τάξεις του χωρίς να το καλέσουμε.
- Δημιουργήστε μια συνάρτηση με το όνομα test που λαμβάνει μια ακέραια παράμετρο i. Το { σηματοδοτεί την αρχή της δοκιμής του σώματος της λειτουργίας.
- Δήλωση που πρέπει να εκτελεστεί εάν κληθεί/κληθεί η παραπάνω δοκιμή συνάρτησης.
- Τέλος του σώματος του παραπάνω λειτουργικού τεστ.
- Δημιουργήστε μια συνάρτηση με το όνομα test που λαμβάνει μια παράμετρο float f. Το { σηματοδοτεί την αρχή της δοκιμής του σώματος της λειτουργίας.
- Δήλωση που πρέπει να εκτελεστεί εάν κληθεί/κληθεί η παραπάνω δοκιμή συνάρτησης.
- Τέλος του σώματος του παραπάνω τεστ λειτουργίας.
- Δημιουργήστε μια συνάρτηση με το όνομα test που λαμβάνει μια παράμετρο χαρακτήρα κεφ. Το { σηματοδοτεί την αρχή της δοκιμής του σώματος της λειτουργίας.
- Δήλωση που πρέπει να εκτελεστεί εάν κληθεί/κληθεί η παραπάνω δοκιμή συνάρτησης.
- Τέλος του σώματος του παραπάνω τεστ λειτουργίας.
- Καλέστε τη συνάρτηση main(). Το { σηματοδοτεί την αρχή του σώματος της συνάρτησης.
- Καλέστε τη δοκιμή συνάρτησης και περνώντας της το 5 ως τιμή του ορίσματος. Αυτό καλεί τη συνάρτηση δοκιμής που δέχεται ένα ακέραιο όρισμα, δηλαδή την πρώτη δοκιμαστική συνάρτηση.
- Καλέστε τη δοκιμή συνάρτησης και περάστε την 5.5 ως τιμή του ορίσματος. Αυτό θα ενεργοποιήσει τη συνάρτηση δοκιμής που δέχεται ένα όρισμα float, δηλαδή τη δεύτερη συνάρτηση δοκιμής.
- Καλέστε τη δοκιμή συνάρτησης και περάστε πέντε σε αυτήν ως τιμή του ορίσματος. Αυτό θα ενεργοποιήσει τη συνάρτηση δοκιμής που δέχεται ένα όρισμα χαρακτήρα, δηλαδή την τρίτη συνάρτηση δοκιμής.
- Το πρόγραμμα πρέπει να επιστρέψει μια τιμή εάν εκτελείται με επιτυχία.
- Το τέλος του σώματος της συνάρτησης main().
Έχουμε τρεις συναρτήσεις με το ίδιο όνομα αλλά διαφορετικούς τύπους ορισμάτων. Έχουμε πετύχει πολυμορφισμό.
Operator Υπερφόρτωση
In Operator Υπερφόρτωση, ορίζουμε μια νέα σημασία για το α C++ χειριστής. Αλλάζει επίσης τον τρόπο λειτουργίας του χειριστή. Για παράδειγμα, μπορούμε να ορίσουμε τον τελεστή + για τη σύνδεση δύο συμβολοσειρών. Τον γνωρίζουμε ως τον τελεστή πρόσθεσης για την προσθήκη αριθμητικών τιμών. Μετά τον ορισμό μας, όταν τοποθετηθεί μεταξύ ακεραίων, θα τους προσθέσει. Όταν τοποθετηθεί ανάμεσα σε χορδές, θα τις ενώσει.
Παράδειγμα 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(); }
Παραγωγή:
Εδώ είναι ένα στιγμιότυπο οθόνης του κώδικα:
Επεξήγηση κώδικα:
- Συμπεριλάβετε το αρχείο κεφαλίδας iostream στο πρόγραμμά μας για να χρησιμοποιήσετε τις λειτουργίες του.
- Συμπεριλάβετε τον χώρο ονομάτων std στο πρόγραμμά μας για να χρησιμοποιήσετε τις κλάσεις του χωρίς να τον καλέσετε.
- Δημιουργήστε μια κλάση με το όνομα ComplexNum. Το { σηματοδοτεί την αρχή του σώματος της τάξης.
- Χρησιμοποιήστε τον τροποποιητή ιδιωτικής πρόσβασης για να επισημάνετε τις μεταβλητές ως ιδιωτικές, που σημαίνει ότι μπορούν να προσπελαστούν μόνο μέσα από την κλάση.
- Ορίστε δύο ακέραιες μεταβλητές, πραγματικές και πάνω.
- Χρησιμοποιήστε τον τροποποιητή δημόσιας πρόσβασης για να επισημάνετε τον κατασκευαστή ως δημόσιο, που σημαίνει ότι θα είναι προσβάσιμος ακόμη και εκτός του τάξη.
- Δημιουργήστε τον κατασκευαστή κλάσης και αρχικοποιήστε τις μεταβλητές.
- Αρχικοποιήστε την τιμή της μεταβλητής real.
- Αρχικοποιήστε την τιμή της μεταβλητής over.
- Τέλος του σώματος του κατασκευαστή.
- Πρέπει να παρακάμψουμε την έννοια του τελεστή +.
- Δημιουργήστε το αποτέλεσμα τύπου δεδομένων τύπου ComplexNum.
- Χρησιμοποιήστε τον τελεστή + με μιγαδικούς αριθμούς. Αυτή η γραμμή θα προσθέσει το πραγματικό μέρος ενός αριθμού στο πραγματικό μέρος ενός άλλου αριθμού.
- Χρησιμοποιήστε τον τελεστή + με μιγαδικούς αριθμούς. Αυτή η γραμμή θα προσθέσει το φανταστικό μέρος ενός αριθμού στο φανταστικό μέρος ενός άλλου αριθμού.
- Το πρόγραμμα θα επιστρέψει την τιμή του αποτελέσματος της μεταβλητής μετά την επιτυχή εκτέλεση.
- Τέλος του ορισμού της νέας έννοιας του + τελεστή, δηλαδή υπερφόρτωση.
- Καλέστε τη μέθοδο print().
- Εκτυπώστε τον νέο μιγαδικό αριθμό μετά την προσθήκη στην κονσόλα.
- Τέλος του σώματος της συνάρτησης print().
- Τέλος του σώματος της κλάσης ComplexNum.
- Καλέστε τη συνάρτηση main().
- Περάστε τις τιμές τόσο των πραγματικών όσο και των μιγαδικών μερών που θα προστεθούν. Το πρώτο μέρος του c1 θα προστεθεί στο πρώτο μέρος του c2, δηλαδή 10+3. Το δεύτερο μέρος του c1 θα προστεθεί στο δεύτερο μέρος του c, δηλαδή 2+7.
- Εκτελέστε μια λειτουργία χρησιμοποιώντας τον τελεστή overloaded + και αποθηκεύοντας το αποτέλεσμα στη μεταβλητή c3.
- Εκτυπώστε την τιμή της μεταβλητής c3 στην κονσόλα.
- Τέλος του σώματος της συνάρτησης main().
Πολυμορφισμός χρόνου εκτέλεσης
Αυτό συμβαίνει όταν η μέθοδος ενός αντικειμένου καλείται/καλείται κατά τη διάρκεια του χρόνου εκτέλεσης και όχι κατά τη διάρκεια του χρόνου μεταγλώττισης. Ο πολυμορφισμός χρόνου εκτέλεσης επιτυγχάνεται μέσω της παράκαμψης συναρτήσεων. Η συνάρτηση που θα κληθεί/κληθεί καθιερώνεται κατά τη διάρκεια του χρόνου εκτέλεσης.
Παράκαμψη συνάρτησης
Η παράκαμψη συνάρτησης συμβαίνει όταν μια συνάρτηση της βασικής κλάσης λαμβάνει έναν νέο ορισμό σε μια παράγωγη κλάση. Εκείνη τη στιγμή, μπορούμε να πούμε ότι η βασική συνάρτηση έχει παρακαμφθεί.
Για παράδειγμα:
#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; }
Παραγωγή:
Εδώ είναι ένα στιγμιότυπο οθόνης του κώδικα:
Επεξήγηση κώδικα:
- Εισαγάγετε το αρχείο κεφαλίδας iostream στο πρόγραμμά μας για να χρησιμοποιήσετε τις λειτουργίες του.
- Συμπεριλάβετε τον χώρο ονομάτων std στο πρόγραμμά μας για να χρησιμοποιήσετε τις κλάσεις του χωρίς να τον καλέσετε.
- Δημιουργήστε μια τάξη με το όνομα Mammal. Το { σηματοδοτεί την αρχή του σώματος της τάξης.
- Χρησιμοποιήστε τον τροποποιητή δημόσιας πρόσβασης για να ορίσετε τη συνάρτηση που πρόκειται να δημιουργήσουμε ως δημόσια προσβάσιμη. Θα είναι προσβάσιμο εκτός αυτής της τάξης.
- Δημιουργήστε μια δημόσια λειτουργία με το όνομα eat. Το { σηματοδοτεί την αρχή του σώματος συνάρτησης.
- Εκτυπώστε τη δήλωση που προστέθηκε στη συνάρτηση cout όταν καλείται η συνάρτηση eat().
- Το τέλος του σώματος της συνάρτησης eat().
- Τέλος του σώματος της τάξης Θηλαστικού.
- Δημιουργήστε μια τάξη με το όνομα Cow που κληρονομεί την κατηγορία Mammal. Η αγελάδα είναι η παραγόμενη τάξη, ενώ το Θηλαστικό είναι η βασική κατηγορία. Το { σηματοδοτεί την αρχή αυτής της τάξης.
- Χρησιμοποιήστε τον τροποποιητή δημόσιας πρόσβασης για να επισημάνετε τη συνάρτηση που πρόκειται να δημιουργήσουμε ως δημόσια προσβάσιμη. Θα είναι προσβάσιμο εκτός αυτής της τάξης.
- Παράκαμψη της συνάρτησης eat() που ορίστηκε στη βασική κλάση. Το { σηματοδοτεί την αρχή του σώματος συνάρτησης.
- Η δήλωση για εκτύπωση στην κονσόλα όταν καλείται αυτή η λειτουργία.
- Τέλος του σώματος της συνάρτησης eat().
- Τέλος του σώματος της τάξης Αγελάδα.
- Καλέστε τη συνάρτηση main(). Το { σηματοδοτεί την αρχή του σώματος αυτής της συνάρτησης.
- Δημιουργήστε ένα στιγμιότυπο της κλάσης Cow και δώστε της το όνομα c.
- Καλέστε τη συνάρτηση eat() που ορίζεται στην κλάση Cow.
- Το πρόγραμμα πρέπει να επιστρέψει μια τιμή μετά την επιτυχή ολοκλήρωση.
- Τέλος της συνάρτησης main().
C++ Εικονική λειτουργία
Μια εικονική συνάρτηση είναι ένας άλλος τρόπος υλοποίησης του πολυμορφισμού χρόνου εκτέλεσης C++. Είναι μια ειδική συνάρτηση που ορίζεται σε μια βασική κλάση και επαναπροσδιορίζεται στην παράγωγη κλάση. Για να δηλώσετε μια εικονική συνάρτηση, θα πρέπει να χρησιμοποιήσετε την εικονική λέξη-κλειδί. Η λέξη-κλειδί πρέπει να προηγείται της δήλωσης της συνάρτησης στη βασική κλάση.
Εάν μια κλάση εικονικής συνάρτησης κληρονομηθεί, η εικονική κλάση επαναπροσδιορίζει την εικονική συνάρτηση για να ταιριάζει στις ανάγκες της. Για παράδειγμα:
#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(); }
Παραγωγή:
Εδώ είναι ένα στιγμιότυπο οθόνης του κώδικα:
Επεξήγηση κώδικα:
- Συμπεριλάβετε το αρχείο κεφαλίδας iostream στον κώδικα για να χρησιμοποιήσετε τις λειτουργίες του.
- Συμπεριλάβετε τον χώρο ονομάτων std στον κώδικά μας για να χρησιμοποιήσετε τις κλάσεις του χωρίς να τον καλέσετε.
- Δημιουργήστε μια τάξη με το όνομα ClassA.
- Χρησιμοποιήστε τον τροποποιητή δημόσιας πρόσβασης για να επισημάνετε ένα μέλος της τάξης ως δημόσια προσβάσιμο.
- Δημιουργήστε μια εικονική συνάρτηση με το όνομα show(). Θα είναι δημόσια λειτουργία.
- Το κείμενο που πρέπει να εκτυπωθεί όταν καλείται η show() που επικαλείται. Το endl είναι α C++ λέξη-κλειδί, που σημαίνει τελική γραμμή. Μετακινεί τον κέρσορα του ποντικιού στην επόμενη γραμμή.
- Τέλος του σώματος της εικονικής συνάρτησης show().
- Τέλος του σώματος της τάξης ClassA.
- Δημιουργία μιας νέας κλάσης με το όνομα ClassB που κληρονομεί την κλάση ClassA. Η ClassA γίνεται η βασική κλάση ενώ η ClassB η παραγόμενη κλάση.
- Χρησιμοποιήστε τον τροποποιητή δημόσιας πρόσβασης για να επισημάνετε ένα μέλος της τάξης ως δημόσια προσβάσιμο.
- Επαναπροσδιορίστε την εικονική συνάρτηση show() που προέρχεται από τη βασική κλάση.
- Το κείμενο που θα εκτυπωθεί στην κονσόλα όταν καλείται η συνάρτηση show() που ορίζεται στην παράγωγη κλάση.
- Τέλος του σώματος της συνάρτησης show().
- Τέλος του σώματος της παραγόμενης κλάσης, ClassB.
- Καλέστε τη συνάρτηση main(). Η λογική του προγράμματος πρέπει να προστεθεί στο σώμα του.
- Δημιουργήστε μια μεταβλητή δείκτη με το όνομα a. Δείχνει την κλάση με το όνομα ClassA.
- Δημιουργήστε ένα στιγμιότυπο της κλάσης με το όνομα ClassB. Στο παράδειγμα δίνεται το όνομα β.
- Αντιστοιχίστε τις τιμές που αποθηκεύονται στη διεύθυνση b στη μεταβλητή a.
- Καλέστε τη συνάρτηση show() που ορίζεται στην παράγωγη κλάση. Έχει εφαρμοστεί καθυστερημένη δέσμευση.
- Τέλος του σώματος της συνάρτησης main().
Compile-Time Polymorphism Vs. Πολυμορφισμός χρόνου εκτέλεσης
Εδώ είναι οι κύριες διαφορές μεταξύ των δύο:
Πολυμορφισμός μεταγλώττισης | Πολυμορφισμός χρόνου εκτέλεσης |
---|---|
Ονομάζεται επίσης πρώιμος δεσμευτικός ή στατικός πολυμορφισμός | Ονομάζεται επίσης όψιμος/δυναμικός δεσμευτικός ή δυναμικός πολυμορφισμός |
Η μέθοδος καλείται/καλείται κατά τη διάρκεια του χρόνου μεταγλώττισης | Η μέθοδος καλείται/καλείται κατά τη διάρκεια του χρόνου εκτέλεσης |
Υλοποιείται μέσω υπερφόρτωσης λειτουργίας και υπερφόρτωσης χειριστή | Υλοποιείται μέσω παράκαμψης μεθόδου και εικονικών συναρτήσεων |
Παράδειγμα, υπερφόρτωση μεθόδου. Πολλές μέθοδοι μπορεί να έχουν παρόμοια ονόματα αλλά διαφορετικό αριθμό ή τύπους ορισμάτων | Παράδειγμα, παράκαμψη μεθόδου. Πολλές μέθοδοι μπορεί να έχουν παρόμοιο όνομα και ίδιο πρωτότυπο. |
Ταχύτερη εκτέλεση αφού η ανακάλυψη των μεθόδων γίνεται κατά τη διάρκεια του χρόνου μεταγλώττισης | Πιο αργή εκτέλεση αφού ο εντοπισμός μεθόδου γίνεται κατά τη διάρκεια του χρόνου εκτέλεσης. |
Less παρέχεται ευελιξία για την επίλυση προβλημάτων αφού όλα είναι γνωστά κατά τη διάρκεια του χρόνου μεταγλώττισης. | Παρέχεται μεγάλη ευελιξία για την επίλυση πολύπλοκων προβλημάτων αφού οι μέθοδοι ανακαλύπτονται κατά τη διάρκεια του χρόνου εκτέλεσης. |
Σύνοψη
- Πολυμορφισμός σημαίνει να έχεις πολλές μορφές.
- Εμφανίζεται όταν υπάρχει μια ιεραρχία κλάσεων που σχετίζονται μέσω κληρονομικότητας.
- Με τον πολυμορφισμό, μια συνάρτηση μπορεί να συμπεριφέρεται διαφορετικά με βάση το αντικείμενο που την καλεί/καλεί.
- Στον πολυμορφισμό χρόνου μεταγλώττισης, η συνάρτηση που θα κληθεί καθορίζεται κατά τη διάρκεια του χρόνου μεταγλώττισης.
- Στον πολυμορφισμό χρόνου εκτέλεσης, η συνάρτηση που θα κληθεί καθιερώνεται κατά τη διάρκεια του χρόνου εκτέλεσης.
- Ο πολυμορφισμός χρόνου μεταγλώττισης προσδιορίζεται μέσω υπερφόρτωσης συναρτήσεων και υπερφόρτωσης χειριστή.
- Στην υπερφόρτωση συναρτήσεων, υπάρχουν πολλές συναρτήσεις με παρόμοια ονόματα αλλά διαφορετικά ορίσματα.
- Οι παράμετροι μπορεί να διαφέρουν ως προς τον αριθμό ή τον τύπο.
- Στην υπερφόρτωση χειριστή, ορίζεται μια νέα έννοια για C++ φορείς.
- Ο πολυμορφισμός χρόνου εκτέλεσης επιτυγχάνεται μέσω της παράκαμψης συναρτήσεων.
- Στην παράκαμψη συνάρτησης, μια παραγόμενη κλάση δίνει έναν νέο ορισμό σε μια συνάρτηση που ορίζεται στη βασική κλάση.