User Tools

Site Tools


cpp:inheritance

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:inheritance [2017/04/22 09:54] – [Άλλες μορφές κληρονομικότητας] gthanoscpp:inheritance [2022/05/13 07:01] (current) – [Κληρονομικότητα] gthanos
Line 1: Line 1:
 ====== Κληρονομικότητα ====== ====== Κληρονομικότητα ======
  
-====== Κληρονομικότητα ======+Οι κλάσεις στη C++ μπορούν να επεκταθούν μέσω της κληρονομικότητας, δημιουργώντας νέες κλάσεις που διατηρούν τα χαρακτηριστικά των προγόνων τους. Η κληρονομικότητα προϋποθέτει ότι υπάρχει η βασική κλάση (πρόγονος) από την οποία προκύπτουν μία ή περισσότερες κλάσεις (απόγονοι). Οι απόγονοι διατηρούν τα χαρακτηριστικά του προγόνου, αλλά έχουν την δυνατότητα να προσθέσουν και επιπλέον χαρακτηριστικά στη νέα κλάση.
  
-Σε αναλογία με τη Java, οι κλάσεις στη C++ μπορούν να επεκταθούν μέσω της κληρονομικότητας, δημιουργώντας νέες κλάσεις που διατηρούν τα χαρακτηριστικά των προγόνων τους. Η κληρονομικότητα προϋποθέτει ότι υπάρχει η βασική κλάση (πρόγονος) από την οποία προκύπτουν μία ή περισσότερες κλάσεις (απόγονοι). Οι απόγονοι διατηρούν τα χαρακτηριστικά του προγόνου, αλλά έχουν την δυνατότητα να προσθέσουν και επιπλέον χαρακτηριστικά στη νέα κλάση.+Στο παρακάτω παράδειγμα, από την κλάση //Shape// (διδιάστατο σχήμα) προκύπτει η κλάση //Rectangle// (ορθογώνιο παραλληλόγραμμο). Η κλάση //Shape// ορίζει την //private// μεταβλητή //color// που αφορά το χρώμα του σχήματοςτο οποίο αποθηκεύεται σε μορφή [[wp>RGB]] και την //protected// μεταβλητή //borderWidth// που αφορά το πάχος του πλαισίου γύρο από το σχήμα.
  
-Στο παρακάτω παράδειγμα, από την κλάση //Rectangle// (ορθογώνιο παραλλολόγραμμο) προκύπτει η κλάση //Square// (τετράγωνο). Η κλάση //Square// εκτός των διαστάσεων του τετραγώνου ορίζει μία επιπλέον παράμετρο //color// που αφορά το χρώμα του τετραγώνου και το οποίο αποθηκεύεται σε μορφή [[wp>RGB]]. +<code cpp Shape.hpp
- +class Shape 
-<code cpp Rectangle.cpp> +    unsigned int color;
-#include <iostream> +
-using namespace std; +
- +
-class Rectangle { +
-  private: +
-    int width;+
   protected:   protected:
-    int height;+    unsigned char borderWidth;
   public:   public:
-    Rectangle(int wint h); +    Shape(unsigned int cunsigned char bw); 
-    bool equals(Rectangle &r); +    Shape(unsigned char red, unsigned char blue, unsigned char green, unsigned char bw); 
-    void setWidth(int w); +    void setColor(unsigned int c); 
-    void setHeight(int h); +    void setColor(unsigned char red, unsigned char blue, unsigned char green); 
-    int getWidth(); +    unsigned int getColor(); 
-    int getHeight();+    unsigned int getArea();
 }; };
- 
-Rectangle::Rectangle(int w, int h) { 
-  width = w; height = h; 
-} 
- 
-bool Rectangle::equals(Rectangle &r) { 
-  if(r.width == width && r.height == height) 
-    return true; 
-  return false; 
-} 
- 
-void Rectangle::setWidth(int w) { width = w; } 
-void Rectangle::setHeight(int h) { height = h; } 
-int Rectangle::getWidth() { return width; } 
-int Rectangle::getHeight() { return height; } 
 </code> </code>
  
-<code cpp Square.cpp> +<code cpp Shape.cpp> 
-#include "Rectangle.cpp"+#include <iostream> 
 +using namespace std;
  
-class Square: public Rectangle { +#include "Shape.hpp"
-   int color; +
-   public: +
-     Square(int s); +
-     bool equals(Square &s); +
-     void setColor(int c); +
-     void setColor(unsigned char r, unsigned char b, unsigned char g); +
-     int getColor(); +
-     int getArea(); +
-};+
  
-Square::Square(int s) : Rectangle(s,s) {} +void Shape::setColor(unsigned int c) { color = c; } 
-void Square::setColor(int c) { color = c; } +void Shape::setColor(unsigned char red, unsigned char blue, unsigned char green) {
-void Square::setColor(unsigned char red, unsigned char blue, unsigned char green) {+
   color = red;   color = red;
   color <<= 8;   color <<= 8;
Line 65: Line 35:
 } }
  
-int Square::getColor() {+unsigned int Shape::getColor() {
   return color;   return color;
 } }
  
-int Square::getArea() +Shape::Shape(unsigned int c, unsigned char bw: color(c), borderWidth(bw) {
-  // height is accessible from Square +
-  // since it is a protected member. +
-  return getWidth() * height; +
 } }
  
-bool Square::equals(Square &s) { +Shape::Shape(unsigned char red, unsigned char blue, unsigned char green, unsigned char bw) : borderWidth(bw) { 
-   ifRectangle::equals(s&& s.color == color) +  setColor(red, blue, green);
-     return true; +
-   return false;+
 } }
-</code> 
  
-<code cpp SquareUsage.cpp> +unsigned int Shape::getArea() {
-#include "Square.cpp" +
- +
-int main() { +
-  Square square(5); +
-  cout << "Square dimensions[" << square.getWidth() <<"," << square.getHeight() << "]\n"; +
-  cout << "Square area" << square.getArea() << endl;+
   return 0;   return 0;
 } }
 </code> </code>
  
-Από τα παραπάνω παρατηρούμε τα εξής: +<code cpp Rectangle.hpp> 
-  - Η κληρονομικότητα δηλώνεται μέσω της δήλωσης ''class derived_class_name : public base_class_name { /*...*/ };'' (στο παραπάνω παράδειγμα ''class Square: public Rectangle { };'')+#include "Shape.hpp"
-  - Τα μέλη της γονικής κλάσης //Rectangle// που είναι δηλωμένα ως //protected// είναι προσβάσιμα από την απόγονο κλάση //Square//. Τα μέλη της γονικής κλάσης //Rectangle// που είναι δηλωμένα ως //private// δεν είναι προσβάσιμα από την απόγονο κλάση //Square//+
-  - Όπως και στη Java, τα μέλη της γονικής κλάσης //Rectangle// ή της απογόνου κλάσης Square που είναι δηλωμένα ως //public// είναι προσβάσιμα από οποιαδήποτε κλάση ή μέθοδο.+
  
-Συνοπτικά ο πίνακας προσβασιμότητας παρατίθεται παρακάτω+class Rectangle public Shape { 
-^                  ^  μέλη της γονικής κλάσης  ^^^ +  private: 
-^  προσβασιμότητα  ^  public  ^  protected  private  ^ +    unsigned int width, height;   
-| μέλη της ίδιας κλάσης  |  ναι  |  ναι  |  ναι  | +  public: 
-| μέλη υποκλάσης  |  ναι  |  ναι  |  όχι   | +    Rectangle(unsigned int cunsigned char bwunsigned int wunsigned int h); 
-| μη μέλη της κλάσης  |  ναι  |  όχι  |  όχι +    void setWidth(unsigned int w); 
- +    void setHeight(unsigned int h); 
-<WRAP center round info 80%> +    unsigned int getWidth()
-Όταν μία κλάση έχει πρόσβαση σε ένα πεδίοτο πεδίο αυτό δεν είναι προσβάσιμο μόνο για το τρέχον αντικείμενοαλλά και για όλα αντικείμενα του τύπου της κλάσης. Στο παραπάνω παράδειγμαη μέθοδος //equals// στις κλάσεις //Rectangle// και //Square// έχει πρόσβαση στα πεδία του αντικειμένου της μεθόδου που λαμβάνεται ως όρισμα. +    unsigned int getHeight(); 
-</WRAP> +    unsigned int getArea(); 
- +     
-<WRAP center round info 80%> +    unsigned char getBorderWidth(); 
-Όταν η απόγονος κλάση επαναορίζει μία μέθοδο με το ίδιο signature (ίδιο όνομα, ίδιος αριθμός και τύπος ορισμάτωντότε συχνά θέλουμε να χρησιμοποιήσουμε τη γονική μέθοδο προκειμένου να την επεκτείνουμε. Ο τρόπος χρήσης της γονικής μεθόδου είναι βάζοντας ως πρόθεμα στη μέθοδο το όνομα της γονικής κλάσης. Ο λόγος που δεν υπάρχει κάποια δεσμευμένη λέξη (όπως ο τελεστής //super// στη Javaπου να αναφέρεται στη γονική κλάση είναι η πολλαπλή κληρονομικότητα που επιτρέπει η C++. Από το παραπάνω παράδειγμα, δείτε την υλοποίηση της //equals// στην κλάση //Square//. +    void setBorderWidth(unsigned char bw)
-<code cpp> +};
-  bool Square::equals(Square &s{ +
-    ifRectangle::equals(s&& s.color == color) +
-      return true+
-    return false+
-  }+
 </code> </code>
-</WRAP> 
  
-===== Άλλες μορφές κληρονομικότητας =====+<code cpp Rectangle.cpp> 
 +#include <iostream> 
 +using namespace std;
  
-Εκτός από την κληρονομικότητα τύπου //public// (''class Square: public Rectangle { };'') μπορείτε να έχετε κληρονομικότητα τύπου //protected// και //private//Σε αυτές τις περιπτώσεις η προσβασιμότητα των πεδίων της γονικής κλάσης δίνεται από τον παραπάνω πίνακα +#include "Rectangle.hpp"
-^    είδος κληρονομικότητας  ^^^ +
-^  μέλη της γονικής κλάσης  ^  public  ^  protected  ^  private +
-| public μέλη  |  public  |  protected  |  not accessible +
-| protected μέλη  |  protected  |  protected  |  not accessible   | +
-| private μέλη  |  not accessible  |  not accessible  |  not accessible  |+
  
-Δείτε το παρακάτω παράδειγμα που παραθέτει αναλυτικά τα επίπεδα της προσβασιμότητας+Rectangle::Rectangle(unsigned int c, unsigned char bw, unsigned int w, unsigned int h) :  
 +  Shape(c, bw) , width(w), height(h) { }
  
-<code cpp> +void Rectangle::setWidth(unsigned int w) { width = w} 
-class Parent { +void Rectangle::setHeight(unsigned int h) { height = h} 
-public: +unsigned int Rectangle::getWidth() { return width; } 
-    int publicMember+unsigned int Rectangle::getHeight() { return height; }
-protected: +
-    int protectedMember+
-private+
-    int privateMember; +
-};+
  
-class ChildA public Parent +unsigned int Rectangle::getArea() 
-    // publicMember is public +  /* this is how you call a function  
-    // protectedMember is protected +   * from the parent class. 
-    // privateMember is not accessible from ChildA +   *
-};+  int area = Shape::getArea(); 
 +  return Shape::getArea() + width * height; 
 +}
  
-class ChildB protected Parent { +unsigned char Rectangle::getBorderWidth() return borderWidth; 
-    // publicMember is protected +void Rectangle::setBorderWidth(unsigned char bw{ borderWidth = bw; }
-    // protectedMember is protected +
-    // privateMember is not accessible from ChildB +
-}; +
- +
-class ChildC private Parent {   // 'private' is default for classes +
-    // publicMember is private (accessible) +
-    // protectedMember is private  (accessible) +
-    // privateMember is not accessible from ChildC +
-};+
 </code> </code>
  
-Στο παραπάνω παράδειγμα συμπερασματικά θα μπορούσαμε να πούμε τα εξής: +<code cpp RectangleUsage.cpp> 
-  * Για την κλάση //ChildA// (//public// κληρονομικότητα) οποιαδήποτε κλάση γνωρίζει ότι η //ChildA// είναι απόγονος της //Parent//+#include "Rectangle.hpp" 
-  * Για την κλάση //ChildB// (//protected// κληρονομικότητα), μόνο η κλάση //ChildB// και η απόγονοι αυτής γνωρίζει ότι η //ChildB// είναι απόγονος της //Parent//+#include <iostream> 
-  * Για την κλάση //ChildC// (//private// κληρονομικότητα), μόνο η κλάση //ChildC// γνωρίζει ότι η //ChildC// είναι απόγονος της //Parent//.+using namespace std;
  
-<WRAP center round tip 80%> +int main() { 
-Η κληρονομικότητα τύπου //private// ή //protected// έχει περιορισμένη χρήση+  Rectangle rectangle(0xffffff, 2, 10, 20); 
-</WRAP>+  rectangle.setBorderWidth(8); 
 +   
 +  cout <"[Rectangle Properties] "; 
 +  cout << " color: 0x" << std::hex << rectangle.getColor() << dec; 
 +  cout << " borderWidth: " << (int)rectangle.getBorderWidth(); 
 +  cout << " area: " << rectangle.getArea() << endl; 
 +   
 +  return 0; 
 +} 
 +</code>
  
-===== Πολλαπλή κληρονομικότητα ===== +Από τα παραπάνω παρατηρούμε τα εξής: 
- +  - Η κληρονομικότητα δηλώνεται μέσω της δήλωσης ''class derived_class_name : public base_class_name { /*...*/ };'' (στο παραπάνω παράδειγμα ''class Rectangle: public Shape { };''). 
-Η C++ δίνει την δυνατότητα να έχετε περισσότερες από μία γονικές κλάσεις για μία κλάση απόγονο. Εκ πρώτης όψεως αυτό έρχεται σε αντίθεση με τη Java που επιτρέπει μόνο μία γονική κλάση κατά την διαδικασία της κληρονομικότητας. Γενικά η πολλαπλή κληρομικότητα θα πρέπει να χρησιμοποιείται με πολύ προσοχή και όπου είναι δυνατόν να αποφεύγεται+  - Η απόγονος κλάση μπορεί να ορίσει επιπλέον πεδία και επιπλέον μεθόδους. Η απόγονος κλάση //Rectangle// ορίζει τα επιπλέον πεδία //width, height// και τις επιπλέον μεθόδους //getWidth//, //getHeight//, //setWidth//, //setHeight//
- +  - Η απόγονος κλάση μπορεί να επαναορίσει μία μέθοδο η οποία είναι ήδη ορισμένη στη γονική κλάση. Η απόγονος κλάση //Rectangle// επαναορίζει τη μέθοδο //getArea//
-Παρακάτω δίνεται ένα σχετικά απλό παράδειγμα πολλαπλής κληρονομικότητας.+  - Τα μέλη της γονικής κλάσης //Shape// που είναι δηλωμένα ως //protected// είναι προσβάσιμα από την απόγονο κλάση. Στο παραπάνω παράδειγμα η απόγονος κλάση //Rectangle// έχει πρόσβαση στο //protected// πεδίο //borderWidth// της γονικής κλάσης.  
 +  - Τα μέλη της γονικής κλάσης //Shape// που είναι δηλωμένα ως //private// δεν είναι προσβάσιμα από την απόγονο κλάση //Rectangle//
 +  - Όπως και στη Java, τα μέλη της γονικής κλάσης //Shape// ή της απογόνου κλάσης //Rectangle// που είναι δηλωμένα ως //public// είναι προσβάσιμα από οποιαδήποτε κλάση ή μέθοδο. Για παράδειγμα η //public// μεθόδος //getColor// της κλάσης //Shape// είναι προσβάσιμη από οποιοδήποτε κλάση ή μέθοδο (στο παράδειγμα από τη μέθοδο main).
  
 +Συνοπτικά ο πίνακας προσβασιμότητας παρατίθεται παρακάτω:
 +^                  ^  μέλη της γονικής κλάσης  ^^^
 +^  προσβασιμότητα  ^  public  ^  protected  ^  private  ^
 +| από μεθόδους της ίδιας κλάσης  |  ναι  |  ναι  |  ναι  |
 +| από μεθόδους μίας υποκλάσης  |  ναι  |  ναι  |  όχι   |
 +| από μία άλλη κλάση χωρίς σχέση κληρονομικότητας  |  ναι  |  όχι  |  όχι  |
  
 +===== Κλήση μιας επανα-ορισμένης μεθόδου της γονικής κλάσης από την υποκλάση =====
  
 +Όταν η απόγονος κλάση επαναορίζει μία μέθοδο με το ίδιο //signature// (ίδιο όνομα, ίδιος αριθμός και τύπος ορισμάτων) τότε συχνά θέλουμε να καλέσουμε τη μέθοδο της γονικής κλάσης στην απόγονο κλάση προκειμένου να την επεκτείνουμε. Ο τρόπος κλήσης της γονικής μεθόδου είναι βάζοντας ως πρόθεμα στο όνομα της μεθόδου το όνομα της γονικής κλάσης. Από το παραπάνω παράδειγμα, δείτε την υλοποίηση της συνάρτησης //getArea// στην κλάση //Rectangle// η οποία χρησιμοποιεί την συνάρτηση //getArea// της γονικής κλάσης //Shape//.
 +<code cpp>
 +unsigned int Rectangle::getArea() {
 +  return Shape::getArea() + width * height;
 +}
 +</code>
  
  
cpp/inheritance.1492854864.txt.gz · Last modified: 2017/04/22 08:54 (external edit)