User Tools

Site Tools


cpp:inheritance

This is an old revision of the document!


Κληρονομικότητα

Σε αναλογία με τη Java, οι κλάσεις στη C++ μπορούν να επεκταθούν μέσω της κληρονομικότητας, δημιουργώντας νέες κλάσεις που διατηρούν τα χαρακτηριστικά των προγόνων τους. Η κληρονομικότητα προϋποθέτει ότι υπάρχει η βασική κλάση (πρόγονος) από την οποία προκύπτουν μία ή περισσότερες κλάσεις (απόγονοι). Οι απόγονοι διατηρούν τα χαρακτηριστικά του προγόνου, αλλά έχουν την δυνατότητα να προσθέσουν και επιπλέον χαρακτηριστικά στη νέα κλάση.

Στο παρακάτω παράδειγμα, από την κλάση Rectangle (ορθογώνιο παραλλολόγραμμο) προκύπτει η κλάση Square (τετράγωνο). Η κλάση Square εκτός των διαστάσεων του τετραγώνου ορίζει μία επιπλέον παράμετρο color που αφορά το χρώμα του τετραγώνου και το οποίο αποθηκεύεται σε μορφή RGB.

Rectangle.cpp
#include <iostream>
using namespace std;
 
class Rectangle {
  private:
    int width;
  protected:
    int height;
  public:
    Rectangle(int w, int h);
    bool equals(Rectangle &r);
    void setWidth(int w);
    void setHeight(int h);
    int getWidth();
    int getHeight();
};
 
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; }
Square.cpp
#include "Rectangle.cpp"
 
class Square: public Rectangle {
   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 Square::setColor(int c) { color = c; }
void Square::setColor(unsigned char red, unsigned char blue, unsigned char green) {
  color = red;
  color <<= 8;
  color |= blue;
  color <<= 8;
  color |= green;
}
 
int Square::getColor() {
  return color;
}
 
int Square::getArea() {
  // height is accessible from Square
  // since it is a protected member.
  return getWidth() * height; 
}
 
bool Square::equals(Square &s) {
   if( Rectangle::equals(s) && s.color == color)
     return true;
   return false;
}
SquareUsage.cpp
#include "Square.cpp"
 
int main() {
  Square square(5);
  cout << "Square dimensions: [" << square.getWidth() <<"," << square.getHeight() << "]\n";
  cout << "Square area: " << square.getArea() << endl;
  return 0;
}

Από τα παραπάνω παρατηρούμε τα εξής:

  1. Η κληρονομικότητα δηλώνεται μέσω της δήλωσης class derived_class_name : public base_class_name { }; (στο παραπάνω παράδειγμα class Square: public Rectangle { };).
  2. Τα μέλη της γονικής κλάσης Rectangle που είναι δηλωμένα ως protected είναι προσβάσιμα από την απόγονο κλάση Square. Τα μέλη της γονικής κλάσης Rectangle που είναι δηλωμένα ως private δεν είναι προσβάσιμα από την απόγονο κλάση Square.
  3. Όπως και στη Java, τα μέλη της γονικής κλάσης Rectangle ή της απογόνου κλάσης Square που είναι δηλωμένα ως public είναι προσβάσιμα από οποιαδήποτε κλάση ή μέθοδο.

Συνοπτικά ο πίνακας προσβασιμότητας παρατίθεται παρακάτω:

μέλη της γονικής κλάσης
προσβασιμότητα public protected private
μέλη της ίδιας κλάσης ναι ναι ναι
μέλη υποκλάσης ναι ναι όχι
μη μέλη της κλάσης ναι όχι όχι

Όταν μία κλάση έχει πρόσβαση σε ένα πεδίο, το πεδίο αυτό δεν είναι προσβάσιμο μόνο για το τρέχον αντικείμενο, αλλά και για όλα αντικείμενα του τύπου της κλάσης. Στο παραπάνω παράδειγμα, η μέθοδος equals στις κλάσεις Rectangle και Square έχει πρόσβαση στα πεδία του αντικειμένου της μεθόδου που λαμβάνεται ως όρισμα.

Όταν η απόγονος κλάση επαναορίζει μία μέθοδο με το ίδιο signature (ίδιο όνομα, ίδιος αριθμός και τύπος ορισμάτων) τότε συχνά θέλουμε να χρησιμοποιήσουμε τη γονική μέθοδο προκειμένου να την επεκτείνουμε. Ο τρόπος χρήσης της γονικής μεθόδου είναι βάζοντας ως πρόθεμα στη μέθοδο το όνομα της γονικής κλάσης. Ο λόγος που δεν υπάρχει κάποια δεσμευμένη λέξη (όπως ο τελεστής super στη Java) που να αναφέρεται στη γονική κλάση είναι η πολλαπλή κληρονομικότητα που επιτρέπει η C++. Από το παραπάνω παράδειγμα, δείτε την υλοποίηση της equals στην κλάση Square.

  bool Square::equals(Square &s) {
    if( Rectangle::equals(s) && s.color == color)
      return true;
    return false;
  }

Άλλες μορφές κληρονομικότητας

Εκτός από την κληρονομικότητα τύπου public (class Square: public Rectangle { };) μπορείτε να έχετε κληρονομικότητα τύπου protected και private. Σε αυτές τις περιπτώσεις η προσβασιμότητα των πεδίων της γονικής κλάσης δίνεται από τον παραπάνω πίνακα

είδος κληρονομικότητας
μέλη της γονικής κλάσης public protected private
public μέλη public protected not accessible
protected μέλη protected protected not accessible
private μέλη not accessible not accessible not accessible

Δείτε το παρακάτω παράδειγμα που παραθέτει αναλυτικά τα επίπεδα της προσβασιμότητας

class Parent {
public:
    int publicMember;
protected:
    int protectedMember;
private:
    int privateMember;
};
 
class ChildA : public Parent {
    // publicMember is public
    // protectedMember is protected
    // privateMember is not accessible from ChildA
};
 
class ChildB : protected Parent {
    // publicMember is protected
    // 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
};

Στο παραπάνω παράδειγμα συμπερασματικά θα μπορούσαμε να πούμε τα εξής:

  • Για την κλάση ChildA (public κληρονομικότητα) οποιαδήποτε κλάση γνωρίζει ότι η ChildA είναι απόγονος της Parent.
  • Για την κλάση ChildB (protected κληρονομικότητα), μόνο η κλάση ChildB και η απόγονοι αυτής γνωρίζει ότι η ChildB είναι απόγονος της Parent.
  • Για την κλάση ChildC (private κληρονομικότητα), μόνο η κλάση ChildC γνωρίζει ότι η ChildC είναι απόγονος της Parent.

Η κληρονομικότητα τύπου private ή protected έχει περιορισμένη χρήση.

cpp/inheritance.1492883071.txt.gz · Last modified: 2017/04/22 16:44 (external edit)