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/05/11 08:32] 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 {
-#include <string> +
-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>
  
-void Shape2D::setColor(unsigned int c) { color = c; } +<code cpp Shape.cpp> 
-void Shape2D::setColor(unsigned char red, unsigned char blue, unsigned char green) {+#include <iostream> 
 +using namespace std; 
 + 
 +#include "Shape.hpp" 
 + 
 +void Shape::setColor(unsigned int c) { color = c; } 
 +void Shape::setColor(unsigned char red, unsigned char blue, unsigned char green) {
   color = red;   color = red;
   color <<= 8;   color <<= 8;
Line 37: 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) { 
-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 Shape {
- +
-class Rectangle : public Shape2D {+
   private:   private:
     unsigned int width, height;       unsigned int width, height;  
Line 72: Line 64:
     unsigned int getHeight();     unsigned int getHeight();
     unsigned int getArea();     unsigned int getArea();
 +    
 +    unsigned char getBorderWidth();
 +    void setBorderWidth(unsigned char bw);
 }; };
 +</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 83: Line 85:
  
 unsigned int Rectangle::getArea() { unsigned int Rectangle::getArea() {
-  return Shape2D::getArea() + 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 103: 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// επαναορίζει τη μέθοδο //getArea//.   - Η απόγονος κλάση μπορεί να επαναορίσει μία μέθοδο η οποία είναι ήδη ορισμένη στη γονική κλάση. Η απόγονος κλάση //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%> +Όταν η απόγονος κλάση επαναορίζει μία μέθοδο με το ίδιο //signature// (ίδιο όνομα, ίδιος αριθμός και τύπος ορισμάτων) τότε συχνά θέλουμε να καλέσουμε τη μέθοδο της γονικής κλάσης στην απόγονο κλάση προκειμένου να την επεκτείνουμε. Ο τρόπος κλήσης της γονικής μεθόδου είναι βάζοντας ως πρόθεμα στο όνομα της μεθόδου το όνομα της γονικής κλάσης. Από το παραπάνω παράδειγμα, δείτε την υλοποίηση της συνάρτησης //getArea// στην κλάση //Rectangle// η οποία χρησιμοποιεί την συνάρτηση //getArea// της γονικής κλάσης //Shape//.
-Όταν η απόγονος κλάση επαναορίζει μία μέθοδο με το ίδιο signature (ίδιο όνομα, ίδιος αριθμός και τύπος ορισμάτων) τότε συχνά θέλουμε να χρησιμοποιήσουμε τη γονική μέθοδο προκειμένου να την επεκτείνουμε. Ο τρόπος χρήσης της γονικής μεθόδου είναι βάζοντας ως πρόθεμα στη μέθοδο το όνομα της γονικής κλάσης. Από το παραπάνω παράδειγμα, δείτε την υλοποίηση της συνάρτησης //getArea// στην κλάση //Rectangle// η οποία χρησιμοποιεί την συνάρτηση //getArea// της γονικής κλάσης //Shape2D//.+
 <code cpp> <code cpp>
 unsigned int Rectangle::getArea() { unsigned int Rectangle::getArea() {
-  return Shape2D::getArea() + width * height;+  return Shape::getArea() + width * height;
 } }
 </code> </code>
-</WRAP> 
  
  
cpp/inheritance.1494491556.txt.gz · Last modified: 2017/05/11 07:32 (external edit)