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/25 08:20] gthanoscpp:inheritance [2022/05/13 07:01] (current) – [Κληρονομικότητα] gthanos
Line 1: Line 1:
 ====== Κληρονομικότητα ====== ====== Κληρονομικότητα ======
  
-Σε αναλογία με τη Java, οι κλάσεις στη C++ μπορούν να επεκταθούν μέσω της κληρονομικότητας, δημιουργώντας νέες κλάσεις που διατηρούν τα χαρακτηριστικά των προγόνων τους. Η κληρονομικότητα προϋποθέτει ότι υπάρχει η βασική κλάση (πρόγονος) από την οποία προκύπτουν μία ή περισσότερες κλάσεις (απόγονοι). Οι απόγονοι διατηρούν τα χαρακτηριστικά του προγόνου, αλλά έχουν την δυνατότητα να προσθέσουν και επιπλέον χαρακτηριστικά στη νέα κλάση.+Οι κλάσεις στη C++ μπορούν να επεκταθούν μέσω της κληρονομικότητας, δημιουργώντας νέες κλάσεις που διατηρούν τα χαρακτηριστικά των προγόνων τους. Η κληρονομικότητα προϋποθέτει ότι υπάρχει η βασική κλάση (πρόγονος) από την οποία προκύπτουν μία ή περισσότερες κλάσεις (απόγονοι). Οι απόγονοι διατηρούν τα χαρακτηριστικά του προγόνου, αλλά έχουν την δυνατότητα να προσθέσουν και επιπλέον χαρακτηριστικά στη νέα κλάση.
  
-Στο παρακάτω παράδειγμα, από την κλάση //Shape2D// (διδιάστατο σχήμα) προκύπτει η κλάση //Rectangle// (ορθογώνιο παραλληλόγραμμο). Η κλάση //Shape2D// ορίζει την //private// μεταβλητή //color// που αφορά το χρώμα του τετραγώνου και το οποίο αποθηκεύεται σε μορφή [[wp>RGB]] και την //protected// μεταβλητή //borderWidth// που αφορά το πάχος του πλαισίου γύρο από το σχήμα.+Στο παρακάτω παράδειγμα, από την κλάση //Shape// (διδιάστατο σχήμα) προκύπτει η κλάση //Rectangle// (ορθογώνιο παραλληλόγραμμο). Η κλάση //Shape// ορίζει την //private// μεταβλητή //color// που αφορά το χρώμα του σχήματος, το οποίο αποθηκεύεται σε μορφή [[wp>RGB]] και την //protected// μεταβλητή //borderWidth// που αφορά το πάχος του πλαισίου γύρο από το σχήμα.
  
-<code cpp Shape2D.cpp> +<code cpp Shape.hpp
-#include <iostream> +class Shape {
-using namespace std; +
- +
-#ifndef __SHAPE2D__ +
-#define __SHAPE2D__ +
- +
-class Shape2D {+
     unsigned int color;     unsigned int color;
   protected:   protected:
     unsigned char borderWidth;     unsigned char borderWidth;
   public:   public:
-    Shape2D(unsigned int c, unsigned char bw); +    Shape(unsigned int c, unsigned char bw); 
-    Shape2D(unsigned char red, unsigned char blue, unsigned char green, unsigned char bw);+    Shape(unsigned char red, unsigned char blue, unsigned char green, unsigned char bw);
     void setColor(unsigned int c);     void setColor(unsigned int c);
     void setColor(unsigned char red, unsigned char blue, unsigned char green);     void setColor(unsigned char red, unsigned char blue, unsigned char green);
     unsigned int getColor();     unsigned int getColor();
-    unsigned char getBorderWidth(); 
-    void setBorderWidth(unsigned char bw); 
     unsigned int getArea();     unsigned int getArea();
 }; };
 +</code>
 +
 +<code cpp Shape.cpp>
 +#include <iostream>
 +using namespace std;
 +
 +#include "Shape.hpp"
  
-void Shape2D::setColor(unsigned int c) { color = c; } +void Shape::setColor(unsigned int c) { color = c; } 
-void Shape2D::setColor(unsigned char red, unsigned char blue, unsigned char green) {+void Shape::setColor(unsigned char red, unsigned char blue, unsigned char green) {
   color = red;   color = red;
   color <<= 8;   color <<= 8;
Line 36: Line 35:
 } }
  
-unsigned int Shape2D::getColor() {+unsigned int Shape::getColor() {
   return color;   return color;
 } }
  
-Shape2D::Shape2D(unsigned int c, unsigned char bw) : color(c), borderWidth(bw) { +Shape::Shape(unsigned int c, unsigned char bw) : color(c), borderWidth(bw) {
-  cout << "Color: 0x" << hex << color << dec; +
-  cout << " BorderWidth: " << borderWidth << endl;+
 } }
-Shape2D::Shape2D(unsigned char red, unsigned char blue, unsigned char green, unsigned char bw) : borderWidth(bw) {+ 
 +Shape::Shape(unsigned char red, unsigned char blue, unsigned char green, unsigned char bw) : borderWidth(bw) {
   setColor(red, blue, green);   setColor(red, blue, green);
 } }
  
-unsigned int Shape2D::getArea() {+unsigned int Shape::getArea() {
   return 0;   return 0;
 } }
- 
-unsigned char Shape2D::getBorderWidth() { return borderWidth; } 
-void Shape2D::setBorderWidth(unsigned char bw) { borderWidth = bw; } 
-#endif 
 </code> </code>
  
-<code cpp Rectangle.cpp> +<code cpp Rectangle.hpp
-#include <iostream> +#include "Shape.hpp"
-using namespace std; +
- +
-#include "Shape2D.cpp"+
  
-class Rectangle : public Shape2D {+class Rectangle : public Shape {
   private:   private:
     unsigned int width, height;       unsigned int width, height;  
Line 72: Line 63:
     unsigned int getWidth();     unsigned int getWidth();
     unsigned int getHeight();     unsigned int getHeight();
 +    unsigned int getArea();
 +    
     unsigned char getBorderWidth();     unsigned char getBorderWidth();
     void setBorderWidth(unsigned char bw);     void setBorderWidth(unsigned char bw);
-    unsigned int getArea(); 
 }; };
 +</code>
 +
 +<code cpp Rectangle.cpp>
 +#include <iostream>
 +using namespace std;
 +
 +#include "Rectangle.hpp"
  
 Rectangle::Rectangle(unsigned int c, unsigned char bw, unsigned int w, unsigned int h) :  Rectangle::Rectangle(unsigned int c, unsigned char bw, unsigned int w, unsigned int h) : 
-  Shape2D(c, bw) , width(w), height(h) { }+  Shape(c, bw) , width(w), height(h) { }
  
 void Rectangle::setWidth(unsigned int w) { width = w; } void Rectangle::setWidth(unsigned int w) { width = w; }
Line 84: Line 83:
 unsigned int Rectangle::getWidth() { return width; } unsigned int Rectangle::getWidth() { return width; }
 unsigned int Rectangle::getHeight() { return height; } unsigned int Rectangle::getHeight() { return height; }
- 
-unsigned char Rectangle::getBorderWidth() { return borderWidth; } 
-void Rectangle::setBorderWidth(unsigned char bw) { borderWidth = bw; } 
  
 unsigned int Rectangle::getArea() { unsigned int Rectangle::getArea() {
-  return width * height;+  /* this is how you call a function  
 +   * from the parent class. 
 +   */ 
 +  int area = Shape::getArea(); 
 +  return Shape::getArea() + width * height;
 } }
 +
 +unsigned char Rectangle::getBorderWidth() { return borderWidth; }
 +void Rectangle::setBorderWidth(unsigned char bw) { borderWidth = bw; }
 </code> </code>
  
-<code cpp ShapeUsage.cpp> +<code cpp RectangleUsage.cpp> 
-#include "Rectangle.cpp"+#include "Rectangle.hpp" 
 +#include <iostream> 
 +using namespace std;
  
 int main() { int main() {
   Rectangle rectangle(0xffffff, 2, 10, 20);   Rectangle rectangle(0xffffff, 2, 10, 20);
 +  rectangle.setBorderWidth(8);
      
   cout << "[Rectangle Properties] ";   cout << "[Rectangle Properties] ";
-  cout << " color: 0x" << hex << rectangle.getColor() << dec;+  cout << " color: 0x" << std::hex << rectangle.getColor() << dec;
   cout << " borderWidth: " << (int)rectangle.getBorderWidth();   cout << " borderWidth: " << (int)rectangle.getBorderWidth();
   cout << " area: " << rectangle.getArea() << endl;   cout << " area: " << rectangle.getArea() << endl;
Line 109: Line 115:
  
 Από τα παραπάνω παρατηρούμε τα εξής: Από τα παραπάνω παρατηρούμε τα εξής:
-  - Η κληρονομικότητα δηλώνεται μέσω της δήλωσης ''class derived_class_name : public base_class_name { /*...*/ };'' (στο παραπάνω παράδειγμα ''class Rectangle: public Shape2D { };'').+  - Η κληρονομικότητα δηλώνεται μέσω της δήλωσης ''class derived_class_name : public base_class_name { /*...*/ };'' (στο παραπάνω παράδειγμα ''class Rectangle: public Shape { };'').
   - Η απόγονος κλάση μπορεί να ορίσει επιπλέον πεδία και επιπλέον μεθόδους. Η απόγονος κλάση //Rectangle// ορίζει τα επιπλέον πεδία //width, height// και τις επιπλέον μεθόδους //getWidth//, //getHeight//, //setWidth//, //setHeight//.   - Η απόγονος κλάση μπορεί να ορίσει επιπλέον πεδία και επιπλέον μεθόδους. Η απόγονος κλάση //Rectangle// ορίζει τα επιπλέον πεδία //width, height// και τις επιπλέον μεθόδους //getWidth//, //getHeight//, //setWidth//, //setHeight//.
-  - Η απόγονος κλάση μπορεί να επαναορίσει μία μέθοδο η οποία είναι ήδη ορισμένη στη γονική κλάση. Η απόγονος κλάση //Rectangle// επαναορίζει τις μεθόδους //setBorderWidth// και //getBorderWidth//. +  - Η απόγονος κλάση μπορεί να επαναορίσει μία μέθοδο η οποία είναι ήδη ορισμένη στη γονική κλάση. Η απόγονος κλάση //Rectangle// επαναορίζει τη μέθοδο //getArea//. 
-  - Τα μέλη της γονικής κλάσης //Shape2D// που είναι δηλωμένα ως //protected// είναι προσβάσιμα από την απόγονο κλάση. Στο παραπάνω παράδειγμα η απόγονος κλάση //Rectangle// έχει πρόσβαση στο //protected// πεδίο //borderWidth// της γονικής κλάης.  +  - Τα μέλη της γονικής κλάσης //Shape// που είναι δηλωμένα ως //protected// είναι προσβάσιμα από την απόγονο κλάση. Στο παραπάνω παράδειγμα η απόγονος κλάση //Rectangle// έχει πρόσβαση στο //protected// πεδίο //borderWidth// της γονικής κλάσης.  
-  - Τα μέλη της γονικής κλάσης //Shape2D// που είναι δηλωμένα ως //private// δεν είναι προσβάσιμα από την απόγονο κλάση //Rectangle//+  - Τα μέλη της γονικής κλάσης //Shape// που είναι δηλωμένα ως //private// δεν είναι προσβάσιμα από την απόγονο κλάση //Rectangle//
-  - Όπως και στη Java, τα μέλη της γονικής κλάσης //Rectangle// ή της απογόνου κλάσης Square που είναι δηλωμένα ως //public// είναι προσβάσιμα από οποιαδήποτε κλάση ή μέθοδο. Για παράδειγμα η //public// μεθόδος //getColor// της κλάσης //Shape2D// είναι προσβάσιμη από οποιοδήποτε κλάση ή μέθοδο (στο παράδειγμα από τη μέθοδο main).+  - Όπως και στη Java, τα μέλη της γονικής κλάσης //Shape// ή της απογόνου κλάσης //Rectangle// που είναι δηλωμένα ως //public// είναι προσβάσιμα από οποιαδήποτε κλάση ή μέθοδο. Για παράδειγμα η //public// μεθόδος //getColor// της κλάσης //Shape// είναι προσβάσιμη από οποιοδήποτε κλάση ή μέθοδο (στο παράδειγμα από τη μέθοδο main).
  
 Συνοπτικά ο πίνακας προσβασιμότητας παρατίθεται παρακάτω: Συνοπτικά ο πίνακας προσβασιμότητας παρατίθεται παρακάτω:
 ^                  ^  μέλη της γονικής κλάσης  ^^^ ^                  ^  μέλη της γονικής κλάσης  ^^^
 ^  προσβασιμότητα  ^  public  ^  protected  ^  private  ^ ^  προσβασιμότητα  ^  public  ^  protected  ^  private  ^
-| μέλη της ίδιας κλάσης  |  ναι  |  ναι  |  ναι +από μεθόδους της ίδιας κλάσης  |  ναι  |  ναι  |  ναι 
-| μέλη υποκλάσης  |  ναι  |  ναι  |  όχι   | +από μεθόδους μίας υποκλάσης  |  ναι  |  ναι  |  όχι   | 
-| μη μέλη της κλάσης  |  ναι  |  όχι  |  όχι  |+από μία άλλη κλάση χωρίς σχέση κληρονομικότητας  |  ναι  |  όχι  |  όχι  |
  
-<WRAP center round info 80%> +===== Κλήση μιας επανα-ορισμένης μεθόδου της γονικής κλάσης από την υποκλάση =====
-Όταν μία κλάση έχει πρόσβαση σε ένα πεδίο, το πεδίο αυτό δεν είναι προσβάσιμο μόνο για το τρέχον αντικείμενο, αλλά και για όλα αντικείμενα του τύπου της κλάσης. Στο παραπάνω παράδειγμα, η μέθοδος //equals// στις κλάσεις //Rectangle// και //Square// έχει πρόσβαση στα πεδία του αντικειμένου της μεθόδου που λαμβάνεται ως όρισμα. +
-</WRAP>+
  
-<WRAP center round info 80%> +Όταν η απόγονος κλάση επαναορίζει μία μέθοδο με το ίδιο //signature// (ίδιο όνομα, ίδιος αριθμός και τύπος ορισμάτων) τότε συχνά θέλουμε να καλέσουμε τη μέθοδο της γονικής κλάσης στην απόγονο κλάση προκειμένου να την επεκτείνουμε. Ο τρόπος κλήσης της γονικής μεθόδου είναι βάζοντας ως πρόθεμα στο όνομα της μεθόδου το όνομα της γονικής κλάσης. Από το παραπάνω παράδειγμαδείτε την υλοποίηση της συνάρτησης //getArea// στην κλάση //Rectangle// η οποία χρησιμοποιεί την συνάρτηση //getArea// της γονικής κλάσης //Shape//.
-Όταν η απόγονος κλάση επαναορίζει μία μέθοδο με το ίδιο signature (ίδιο όνομα, ίδιος αριθμός και τύπος ορισμάτων) τότε συχνά θέλουμε να χρησιμοποιήσουμε τη γονική μέθοδο προκειμένου να την επεκτείνουμε. Ο τρόπος χρήσης της γονικής μεθόδου είναι βάζοντας ως πρόθεμα στη μέθοδο το όνομα της γονικής κλάσης. Ο λόγος που δεν υπάρχει κάποια δεσμευμένη λέξη (όπως ο τελεστής //super// στη Java) που να αναφέρεται στη γονική κλάση είναι η πολλαπλή κληρονομικότητα που επιτρέπει η C++. Από το παραπάνω παράδειγμα, δείτε την υλοποίηση της //equals// στην κλάση //Square//.+
 <code cpp> <code cpp>
-  bool Square::equals(Square &s) { +unsigned int Rectangle::getArea() { 
-    if( Rectangle::equals(s&& s.color == color) +  return Shape::getArea() + width * height
-      return true+}
-    return false; +
-  }+
 </code> </code>
-</WRAP> 
  
  
cpp/inheritance.1493108425.txt.gz · Last modified: 2017/04/25 07:20 (external edit)