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 12:21] 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>
 #include "Rectangle.cpp" #include "Rectangle.cpp"
-#include "Triangle.cpp" 
  
 int main() { int main() {
-  Shape2D shape(0x333333, 5); +  Shape shape(0x333333, 5); 
-  Shape2D &shape_ref = shape, *shape_ptr = &shape;+  Shape &shape_ref = shape, *shape_ptr = &shape;
   Rectangle rectangle(0xffffff, 2, 10, 20);   Rectangle rectangle(0xffffff, 2, 10, 20);
-  Shape2D &rect_ref = rectangle, *rect_ptr = &rectangle;+  Shape &rect_ref = rectangle, *rect_ptr = &rectangle;
  
-  cout << "Shape2D area: " << shape.getArea() << endl; +  cout << "Shape area: " << shape.getArea() << endl; 
-  cout << "Shape2D reference area: " << shape_ref.getArea() << endl; +  cout << "Shape reference area: " << shape_ref.getArea() << endl; 
-  cout << "Shape2D pointer area: " << shape_ptr->getArea() << endl;+  cout << "Shape pointer area: " << shape_ptr->getArea() << endl;
   cout << endl;   cout << endl;
   cout << "Rectangle area: " << rectangle.getArea() << endl;   cout << "Rectangle area: " << rectangle.getArea() << endl;
Line 25: Line 24:
 Μεταγλωττίζοντας και εκτελώντας τον παραπάνω κώδικα λαμβάνουμε τα εξής: Μεταγλωττίζοντας και εκτελώντας τον παραπάνω κώδικα λαμβάνουμε τα εξής:
 <code> <code>
-Shape2D area: 0 +Shape area: 0 
-Shape2D reference area: 0 +Shape reference area: 0 
-Shape2D pointer area: 0+Shape pointer area: 0
  
 Rectangle area: 200 Rectangle area: 200
Line 36: Line 35:
 Από τα παραπάνω συμπεραίνουμε ότι η επιλογή κλήσης της μεθόδου //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>
-Shape2D area: 0 +Shape area: 0 
-Shape2D reference area: 0 +Shape reference area: 0 
-Shape2D pointer area: 0+Shape pointer area: 0
  
 Rectangle area: 200 Rectangle area: 200
 Rectangle reference area: 200 Rectangle reference area: 200
 Rectangle 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.1493122874.txt.gz · Last modified: 2017/04/25 11:21 (external edit)