User Tools

Site Tools


cpp:polymorphism

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
cpp:polymorphism [2017/04/25 12:54]
gthanos [Pure Virtual συναρτήσεις και abstract κλάσεις]
cpp:polymorphism [2020/04/15 08:48]
Line 1: Line 1:
-====== Δυναμικός Πολυμορφισμός ====== 
- 
-Ας επανέλθουμε στο αρχικό παράδειγμα της κληρονομικότητας και ας ορίσουμε δύο νέες μεταβλητές α) μία μεταβλητή τύπου δείκτη και μία μεταβλητή τύπου αναφορά σε ένα αντικείμενο τύπου //Shape2D// ως εξής: 
- 
-<code cpp ShapeUsage.cpp> 
-#include "Rectangle.cpp" 
-#include "Triangle.cpp" 
- 
-int main() { 
-  Shape2D shape(0x333333, 5); 
-  Shape2D &shape_ref = shape, *shape_ptr = &shape; 
-  Rectangle rectangle(0xffffff, 2, 10, 20); 
-  Shape2D &rect_ref = rectangle, *rect_ptr = &rectangle; 
- 
-  cout << "Shape2D area: " << shape.getArea() << endl; 
-  cout << "Shape2D reference area: " << shape_ref.getArea() << endl; 
-  cout << "Shape2D pointer area: " << shape_ptr->getArea() << endl; 
-  cout << endl; 
-  cout << "Rectangle area: " << rectangle.getArea() << endl; 
-  cout << "Rectangle reference area: " << rect_ref.getArea() << endl; 
-  cout << "Rectangle pointer area: " << rect_ptr->getArea() << endl; 
- 
-</code> 
- 
-Μεταγλωττίζοντας και εκτελώντας τον παραπάνω κώδικα λαμβάνουμε τα εξής: 
-<code> 
-Shape2D area: 0 
-Shape2D reference area: 0 
-Shape2D pointer area: 0 
- 
-Rectangle area: 200 
-Rectangle reference area: 0 
-Rectangle pointer area: 0 
-</code> 
- 
-Από τα παραπάνω συμπεραίνουμε ότι η επιλογή κλήσης της μεθόδου //getArea// δεν γίνεται δυναμικά με βάση τον τύπο του αντικειμένου στον οποίο δείχνει ο δείκτης ή η αναφορά, αλλά στατικά με βάση τον τύπο δεδομένων για τον οποίο δηλώνεται ο δείκτης ή η αναφορά. Σε αυτή την περίπτωση η επιλογή της μεθόδου γίνεται από τον //compiler// κατά τη μεταγλώττιση του προγράμματος. 
- 
-Εάν θέλουμε η επιλογή της μεθόδου να γίνεται δυναμικά με βάση τον τύπο του αντικειμένου που δείχνει ο δείκτης ή η αναφορά θα πρέπει να δηλώσουμε τη μέθοδο //getArea// στη γονική κλάση //Shape2D// ως //**virtual**// όπως παρακάτω: 
-<code cpp> 
-class Shape2D { 
-  public: 
-    virtual unsigned int getArea(); 
-} 
-unsigned int Shape2D::getArea() { return 0; } 
-</code> 
- 
-Με αυτό τον τρόπο δηλώνουμε προς τον //compiler// ότι η απόφαση για τον ποια μέθοδος θα κληθεί δεν θα ληφθεί κατά τη μεταγλώττιση, αλλά κατά την εκτέλεση του προγράμματος. Δηλώνοντας τη μέθοδο //getArea// ως //**virtual**// στη γονική κλάση το αποτέλεσμα της εκτέλεσης είναι το εξής: 
-<code> 
-Shape2D area: 0 
-Shape2D reference area: 0 
-Shape2D pointer area: 0 
- 
-Rectangle area: 200 
-Rectangle reference area: 200 
-Rectangle pointer area: 200 
-</code> 
- 
-====== Pure Virtual συναρτήσεις και abstract κλάσεις ====== 
- 
-Εκτός από τις //virtual// μεθόδους που είδαμε προηγούμενα μπορούμε να έχουμε και //pure virtual// μεθόδους. Οι μέθοδοι που χαρακτηρίζονται //pure virtual// όταν ορίζονται σε μία κλάση, δηλώνεται μόνο το //prototype// τους, χωρίς να δηλώνεται σώμα και ακολουθεί η δήλωση ''=0''. 
-<code cpp> 
-virtual <return type> <function_name>(<function parameters) =0; 
-</code> 
- 
-Η κλάση που περιέχει μία ή περισσότερες //pure virtual// συναρτήσεις είναι //abstract// και δεν μπορεί να παράγει αντικείμενα, **ακόμη και εάν διαθέτει κατασκευαστή**. Μόνο οι κλάσεις που θα κληρονομήσουν τη συγκεκριμένη κλάση και θα παρέχουν υλοποιήσεις όλων των //pure virtual// μεθόδων θα μπορέσουν να παράγουν αντικείμενα. 
- 
-Για παράδειγμα, στην κλάση //Shape2D// είναι λογικό να δηλώσουμε την μέθοδο //getArea// ως //pure virtual// (αντί να επιστρέφει μηδέν) μιας και η συγκεκριμένη συνάρτηση δεν έχει νόημα για το κλάση //Shape2D//, αλλά μόνο για τις υποκλάσεις αυτής. Η κλάση //Shape2D// διαμορφώνεται ως εξής: 
- 
-<code cpp Shape.cpp> 
-#include <iostream> 
-#include <string> 
-using namespace std; 
- 
-#ifndef __SHAPE2D__ 
-#define __SHAPE2D__ 
- 
-class Shape2D { 
-    unsigned int color; 
-  protected: 
-    unsigned char borderWidth; 
-  public: 
-    Shape2D(unsigned int c, unsigned char bw); 
-    Shape2D(unsigned char red, unsigned char blue, unsigned char green, unsigned char bw); 
-    void setColor(unsigned int c); 
-    void setColor(unsigned char red, unsigned char blue, unsigned char green); 
-    unsigned int getColor(); 
-    unsigned char getBorderWidth(); 
-    void setBorderWidth(unsigned char bw); 
-    virtual unsigned int getArea() = 0; 
-}; 
- 
-void Shape2D::setColor(unsigned int c) { color = c; } 
-void Shape2D::setColor(unsigned char red, unsigned char blue, unsigned char green) { 
-  color = red; 
-  color <<= 8; 
-  color |= blue; 
-  color <<= 8; 
-  color |= green; 
-} 
- 
-unsigned int Shape2D::getColor() { return color; } 
-Shape2D::Shape2D(unsigned int c, unsigned char bw) : color(c), borderWidth(bw) {} 
-Shape2D::Shape2D(unsigned char red, unsigned char blue, unsigned char green, unsigned char bw) : borderWidth(bw) { setColor(red, blue, green); } 
-unsigned char Shape2D::getBorderWidth() { return borderWidth; } 
-void Shape2D::setBorderWidth(unsigned char bw) { borderWidth = bw; } 
-#endif 
-</code> 
- 
-Αντίστοιχα, η μέθοδος getArea() της κλάσης //Rectangle// διαμορφώνεται ως εξής: 
-<code cpp> 
-unsigned int Rectangle::getArea() { 
-  return width * height; 
-} 
-</code> 
- 
-Επειδή η κλάση //Shape2D// είναι πλέον //abstract// δεν μπορεί να δώσει αντικείμενα. Έτσι η συνάρτηση //main// διαμορφώνεται ως εξής. 
-<code cpp ShapeUsage.cpp> 
-#include "Rectangle.cpp" 
-#include "Triangle.cpp" 
- 
-int main() { 
-  Rectangle rectangle(0xffffff, 2, 10, 20); 
-  Shape2D &rect_ref = rectangle, *rect_ptr = &rectangle; 
- 
-  cout << "Rectangle area: " << rectangle.getArea() << endl; 
-  cout << "Rectangle reference area: " << rect_ref.getArea() << endl; 
-  cout << "Rectangle pointer area: " << rect_ptr->getArea() << endl; 
- 
-</code> 
- 
  
cpp/polymorphism.txt · Last modified: 2020/04/15 08:48 (external edit)