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 revisionPrevious revision
Next revision
Previous revision
cpp:polymorphism [2017/04/25 09:43] gthanoscpp:polymorphism [Unknown date] (current) – external edit (Unknown date) 127.0.0.1
Line 1: Line 1:
 ====== Δυναμικός Πολυμορφισμός ====== ====== Δυναμικός Πολυμορφισμός ======
  
-Ας επανέλθουμε στο αρχικό παράδειγμα της κληρονομικότητας και ας ορίσουμε δύο νέες μεταβλητές α) μία μεταβλητή τύπου δείκτη και μία μεταβλητή τύπου αναφορά σε ένα αντικείμενο τύπου //Shape2D// ως εξής:+Ας επανέλθουμε στο αρχικό παράδειγμα της κληρονομικότητας και ας ορίσουμε δύο νέες μεταβλητές α) μία μεταβλητή τύπου δείκτη και μία μεταβλητή τύπου αναφορά σε ένα αντικείμενο τύπου //Shape// ως εξής:
  
 <code cpp ShapeUsage.cpp> <code cpp ShapeUsage.cpp>
Line 7: Line 7:
  
 int main() { int main() {
 +  Shape shape(0x333333, 5);
 +  Shape &shape_ref = shape, *shape_ptr = &shape;
   Rectangle rectangle(0xffffff, 2, 10, 20);   Rectangle rectangle(0xffffff, 2, 10, 20);
-  Shape2D &ref = rectangle, *ptr = &rectangle;+  Shape &rect_ref = rectangle, *rect_ptr = &rectangle;
  
 +  cout << "Shape area: " << shape.getArea() << endl;
 +  cout << "Shape reference area: " << shape_ref.getArea() << endl;
 +  cout << "Shape pointer area: " << shape_ptr->getArea() << endl;
 +  cout << endl;
   cout << "Rectangle area: " << rectangle.getArea() << endl;   cout << "Rectangle area: " << rectangle.getArea() << endl;
-  cout << "Reference area: " << ref.getArea() << endl; +  cout << "Rectangle reference area: " << rect_ref.getArea() << endl; 
-  cout << "Pointer area: " << ptr->getArea() << endl;   +  cout << "Rectangle pointer area: " << rect_ptr->getArea() << endl; 
-   +
-  return 0+
-}+
 </code> </code>
  
 Μεταγλωττίζοντας και εκτελώντας τον παραπάνω κώδικα λαμβάνουμε τα εξής: Μεταγλωττίζοντας και εκτελώντας τον παραπάνω κώδικα λαμβάνουμε τα εξής:
 <code> <code>
 +Shape area: 0
 +Shape reference area: 0
 +Shape pointer area: 0
 +
 Rectangle area: 200 Rectangle area: 200
-Reference area: 0 +Rectangle reference area: 0 
-Pointer area: 0+Rectangle pointer area: 0
 </code> </code>
  
 Από τα παραπάνω συμπεραίνουμε ότι η επιλογή κλήσης της μεθόδου //getArea// δεν γίνεται δυναμικά με βάση τον τύπο του αντικειμένου στον οποίο δείχνει ο δείκτης ή η αναφορά, αλλά στατικά με βάση τον τύπο δεδομένων για τον οποίο δηλώνεται ο δείκτης ή η αναφορά. Σε αυτή την περίπτωση η επιλογή της μεθόδου γίνεται από τον //compiler// κατά τη μεταγλώττιση του προγράμματος. Από τα παραπάνω συμπεραίνουμε ότι η επιλογή κλήσης της μεθόδου //getArea// δεν γίνεται δυναμικά με βάση τον τύπο του αντικειμένου στον οποίο δείχνει ο δείκτης ή η αναφορά, αλλά στατικά με βάση τον τύπο δεδομένων για τον οποίο δηλώνεται ο δείκτης ή η αναφορά. Σε αυτή την περίπτωση η επιλογή της μεθόδου γίνεται από τον //compiler// κατά τη μεταγλώττιση του προγράμματος.
  
-Εάν θέλουμε η επιλογή της μεθόδου να γίνεται δυναμικά με βάση τον τύπο του αντικειμένου που δείχνει ο δείκτης ή η αναφορά θα πρέπει να δηλώσουμε τη μέθοδο //getArea// στη γονική κλάση //Shape2D// ως //**virtual**// όπως παρακάτω:+Εάν θέλουμε η επιλογή της μεθόδου να γίνεται δυναμικά με βάση τον τύπο του αντικειμένου που δείχνει ο δείκτης ή η αναφορά θα πρέπει να δηλώσουμε τη μέθοδο //getArea// στη γονική κλάση //Shape// ως //**virtual**// όπως παρακάτω:
 <code cpp> <code cpp>
-<class Shape2D {+class Shape {
   public:   public:
     virtual unsigned int getArea();     virtual unsigned int getArea();
-+}; 
-unsigned int Shape2D::getArea() { return 0; }+unsigned int Shape::getArea() { return 0; }
 </code> </code>
  
-Με αυτό τον τρόπο δηλώνουμε προς τον //compiler// ότι η απόφαση για τον ποιά μέθοδος θα κληθεί δεν θα ληφθεί κατά τη μεταγλώττιση, αλλά κατά την εκτέλεση του προγράμματος. Δηλώνοντας τη μέθοδο //getArea// ως //**virtual**// στη γονική κλάση το αποτέλεσμα της εκτέλεσης είναι το εξής:+Με αυτό τον τρόπο δηλώνουμε προς τον //compiler// ότι η απόφαση για τον ποια μέθοδος θα κληθεί δεν θα ληφθεί κατά τη μεταγλώττιση, αλλά κατά την εκτέλεση του προγράμματος. Δηλώνοντας τη μέθοδο //getArea// ως //**virtual**// στη γονική κλάση το αποτέλεσμα της εκτέλεσης είναι το εξής:
 <code> <code>
 +Shape area: 0
 +Shape reference area: 0
 +Shape pointer area: 0
 +
 Rectangle area: 200 Rectangle area: 200
-Reference area: 200 +Rectangle reference area: 200 
-Pointer 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// μεθόδων θα μπορέσουν να παράγουν αντικείμενα. 
 + 
 +Για παράδειγμα, στην κλάση //Shape// είναι λογικό να δηλώσουμε την μέθοδο //getArea// ως //pure virtual// (αντί να επιστρέφει μηδέν) μιας και η συγκεκριμένη συνάρτηση δεν έχει νόημα για το κλάση //Shape//, αλλά μόνο για τις υποκλάσεις αυτής. Η κλάση //Shape// διαμορφώνεται ως εξής: 
 + 
 +<code cpp Shape.cpp> 
 +#include <iostream> 
 +#include <string> 
 +using namespace std; 
 + 
 +#ifndef __SHAPE2D__ 
 +#define __SHAPE2D__ 
 + 
 +class Shape { 
 +    unsigned int color; 
 +  protected: 
 +    unsigned char borderWidth; 
 +  public: 
 +    Shape(unsigned int c, unsigned char bw); 
 +    Shape(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 Shape::setColor(unsigned int c) { color = c; } 
 +void Shape::setColor(unsigned char red, unsigned char blue, unsigned char green) { 
 +  color = red; 
 +  color <<= 8; 
 +  color |= blue; 
 +  color <<= 8; 
 +  color |= green; 
 +
 + 
 +unsigned int Shape::getColor() { return color; } 
 +Shape::Shape(unsigned int c, unsigned char bw) : color(c), borderWidth(bw) {} 
 +Shape::Shape(unsigned char red, unsigned char blue, unsigned char green, unsigned char bw) : borderWidth(bw) { setColor(red, blue, green); } 
 +unsigned char Shape::getBorderWidth() { return borderWidth;
 +void Shape::setBorderWidth(unsigned char bw) { borderWidth = bw; } 
 +#endif 
 +</code> 
 + 
 +Αντίστοιχα, η μέθοδος getArea() της κλάσης //Rectangle// διαμορφώνεται ως εξής: 
 +<code cpp> 
 +unsigned int Rectangle::getArea() { 
 +  return width * height; 
 +
 +</code> 
 + 
 +Επειδή η κλάση //Shape// είναι πλέον //abstract// δεν μπορεί να δώσει αντικείμενα. Έτσι η συνάρτηση //main// διαμορφώνεται ως εξής. 
 +<code cpp ShapeUsage.cpp> 
 +#include "Rectangle.cpp" 
 + 
 +int main() { 
 +  Rectangle rectangle(0xffffff, 2, 10, 20); 
 +  Shape &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> </code>
  
  
cpp/polymorphism.1493113426.txt.gz · Last modified: 2017/04/25 08:43 (external edit)