User Tools

Site Tools


cpp:classes

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
Next revisionBoth sides next revision
cpp:classes [2017/04/10 12:54] – created gthanoscpp:classes [2020/04/12 15:08] – [Πεδία που περιγράφονται από κλάσεις] gthanos
Line 1: Line 1:
 ====== Κλάσεις και Αντικείμενα ====== ====== Κλάσεις και Αντικείμενα ======
  
-Όπως και στη Java οι κλάσεις στη C++ δημιουργούν νέους τύπους δεδομένων. Παρακάτω δίνεται ένα παράδειγμα δήλωσης της κλάσης //Rectangle// με παράλληλη δημιουργία ενός αντικειμένου της κλάσης αυτής.+Όπως και στη Java οι κλάσεις στη C++ δημιουργούν νέους τύπους δεδομένων. Παρακάτω δίνεται το παράδειγμα της κλάσης //Rectangle// με παράλληλη δημιουργία ενός αντικειμένου της κλάσης αυτής.
  
 <code c++ Rectangle.cpp> <code c++ Rectangle.cpp>
Line 11: Line 11:
     int width, height;     int width, height;
   public:   public:
-    void set_values (int,int); +    void setWidth(int w); 
-    int area() {return width*height;}+    void setHeight(int h); 
 +    int getWidth(const
 +    int getHeight() const;
 }; };
  
-void Rectangle::set_values (int x, int y) { +void Rectangle::setWidth(int w) { width = w} 
-  width = x+void Rectangle::setHeight(int h) { height = h} 
-  height = y+int Rectangle::getWidth() const { return width; } 
-}+int Rectangle::getHeight() const { return height; }
  
 int main () { int main () {
   Rectangle rect;   Rectangle rect;
-  rect.set_values (3,4); +  rect.setWidth(5); 
-  cout << "area: " << rect.area();+  rect.setHeight(6); 
 +  cout << "area: " << rect.getWidth() * rect.getHeight() << endl;
   return 0;   return 0;
 } }
 </code> </code>
  
-Από τον παραπάνω κώδικα παρατηρούμε τα εξής: +Η παραπάνω κλάση διαθέτει τα πεδία τύπου //int width, height// και τις μεθόδους //setWidth, setHeight, getWidth, getHeight//Η κλάση δεν διαθέτει κατασκευαστή. Η δήλωση ''Rect rect;'' στη μέθοδο //main()// δημιουργεί ένα αντικείμενο με κλήση του //default// κατασκευαστή.
-  - Σε αναλογία με την Java οι κλάσεις περιέχουν πεδία και μεθόδους. +
-  - Μία μέθοδος μπορεί να ορίστεί ολόκληρη μέσα στη δήλωση της κλάσης ή να ορίσει μόνο το prototype μέσα στη δήλωση της κλάσης και τη υλοποιήση της εκτός της κλάσης. Η υλοποίηση της μεθόδου εκτός της κλάσης γίνεται με χρήση του τελεστή ''::'' (δες ''void Rectangle::set_values (int x, int y)''). +
-  - Μπορούμε να περιορίσουμε την προσβασιμότητα των πεδίων και των μεθόδων μίας κλάσης με χρήση //προσδιοριστών πρόσβασης//.+
  
 +===== Διάκριση μεταξύ δήλωσης της κλάσης και υλοποίησης της κλάσης =====
 +
 +Στο προηγούμενο παράδειγμα, η δήλωση της κλάσης και η υλοποίηση των μεθόδων (συναρτήσεων) της κλάσης βρίσκονται στο ίδιο αρχείο. Η δήλωση στο ίδιο αρχείο της κλάσης και των μεθόδων της δεν είναι συνήθης πρακτική. Αντ' αυτού, η δήλωση της κλάσης δηλώνεται σε ένα header file με το όνομα της κλάσης και  κατάληξη ''.hpp'' ή ''.h'', ενώ η υλοποίηση των μεθόδων σε ένα αρχείο ''.cpp'' με το ίδιο όνομα. Η κλάση //Rectangle// που αναφέρεται παραπάνω θα πρέπει να "σπάσει" σε δύο αρχεία ως εξής:
 +
 +<code cpp Rectangle.hpp>
 +#include <iostream>
 +using namespace std;
 +
 +class Rectangle {
 +  private:
 +    int width, height;
 +  public:
 +    void setWidth(int w);
 +    void setHeight(int h);
 +    int getWidth() const;
 +    int getHeight() const;
 +};
 +</code>
 +
 +<code cpp Rectangle.cpp>
 +#include "Rectangle.hpp"
 +
 +void Rectangle::setWidth(int w) { width = w; }
 +void Rectangle::setHeight(int h) { height = h; }
 +int Rectangle::getWidth() const { return width; }
 +int Rectangle::getHeight() const { return height; }
 +</code>
 +
 +Ο λόγος που διακρίνουμε μία κλάση σε δήλωση και υλοποίηση είναι ότι η δήλωση της κλάσης μπορεί να χρειαστεί να συμπεριληφθεί μέσω μιας εντολής ''#include'' από περισσότερα του ενός αρχεία στο ίδιο πρόγραμμα. Η υλοποίηση όμως δεν θέλουμε να συμπεριληφθεί σε περισσότερα του ενός μεταγλωττισμένα αρχεία στο ίδιο πρόγραμμα, διότι ο linker στη συνέχεια θα διαμαρτύρεται ότι η ίδια συνάρτηση υπάρχει περισσότερες από μία φορές μέσα στο πρόγραμμα. Επιπλέον, δεν είναι καλή πρακτική στον αντικειμενοστραφή προγραμματισμό να αποκαλύπτουμε στον προγραμματιστή-χρήστη της κλάσης της εσωτερική υλοποίηση της. Έτσι, μπορούμε να διατηρήσουμε "κρυφή" την υλοποίηση των μεθόδων σε ξεχωριστό αρχείο από τη δήλωση της κλάσης.
 +
 +<WRAP important 80% center round>
 +Στη συνέχεια, για λόγους οικονομίας χώρου και ευκολότερης μεταγλώττισης του κώδικα πολλά παραδείγματα θα εμφανίζουν τη δήλωση της κλάσης και την υλοποίηση των μεθόδων της στο ίδιο αρχείο. Πρέπει να έχετε υπόψη σας ότι αυτό αν και δεν είναι λάθος, μπορεί να εφαρμοστεί μόνο σε πολύ απλά και περιορισμένου εύρους προγράμματα.
 +</WRAP>
 +
 +
 +===== Οι μέθοδοι της κλάσης =====
 +
 +Οι μέθοδοι της κλάσης είναι συναρτήσεις οι οποίες έχουν απευθείας πρόσβαση στα πεδία (μεταβλητές) της κλάσης. Οι μέθοδοι ορίζονται μέσα στην κλάση ή ορίζεται το πρότυπο τους μέσα στην κλάση και η υλοποίηση τους εκτός. Από το παρακάτω παράδειγμα παρατηρήστε τους δύο διαφορετικούς τρόπους ορισμού των μεθόδων //setWidth// και //setHeight//. H υλοποίηση της //setHeight// ορίζεται μέσα στη δήλωση της κλάσης, ενώ η υλοποιηση της //setWidth// έξω από την κλάση.
 +
 +<code c++ Rectangle.hpp>
 +#include <iostream>
 +using namespace std;
 +
 +class Rectangle {
 +  private:
 +    int width, height;
 +  public:
 +    int getWidth() const;
 +    int getHeight() const;
 +    void setWidth(int w);
 +    void setHeight(int h) { height = h; }
 +};
 +
 +</code>
 +
 +<code c++ Rectangle.cpp>
 +#include "Rectangle.hpp"
 +
 +int Rectangle::getWidth() const { return width;}
 +int Rectangle::getHeight() const { return height;}
 +void Rectangle::setWidth(int w) { width = w; }
 +</code>
 +
 +Οι δύο παραπάνω τρόποι ορισμού μιας μεθόδου της κλάσης είναι ισοδύναμοι με την διαφορά ότι η μέθοδος //setHeight// ορίζεται ως //inline// ακόμη και εάν η λέξη //inline// δεν αναφέρεται ρητά. Ο λόγος που η //setHeight// γίνεται //inline// είναι για να αποφευχθεί το πρόβλημα των περισσότερων του ενός ορισμών της ίδιας μεθόδου σε επιμέρους μεταγλωττισμένα αρχεία του ιδίου προγράμματος. Ο //compiler// προλαμβάνει το συγκεκριμένο πρόβλημα κάνοντας την μέθοδο //inline//.
 +
 +Για τον ορισμό της μεθόδου //setWidth// εκτός της κλάσης είναι απαραίτητη η χρήση του ονόματος της κλάσης ακολουθούμενη από το //scope operator// **Rectangle::**setWidth(int w). Η χρήση του //scope operator// εξασφαλίζει ότι η μέθοδος ανήκει στην κλάση και δεν αποτελεί αυτόνομη μέθοδο του προγράμματος.
 +
 +Παρατηρήστε ότι οι μέθοδοι //getWidth// και //getHeight// έχουν το προσδιοριστή **const** αμέσως μετά τη δήλωση τους. Ο προσδιοριστής //const// σε αυτή την περίπτωση, δηλώνει ότι η συγκεκριμένη συνάρτηση **δεν μεταβάλλει το αντικείμενο στο οποίο ανήκει**. Η χρήση του προσδιοριστή //const// αποτελεί α) προστασία προς τον προγραμματιστή που υλοποιεί τη μέθοδο, ώστε σε περίπτωση που προσπαθήσει να γράψει ένα πεδίο της κλάσης η μεταγλώττιση να αποτύχει εμφανίζοντας μήνυμα λάθους και β) δήλωση προς τους προγραμματιστές-χρήστες της κλάσης ότι η συγκεκριμένη συνάρτηση δεν θα μεταβάλλει με οποιονδήποτε τρόπο την κατάσταση του αντικειμένου.
 +
 +===== Πεδία που περιγράφονται από κλάσεις =====
 +
 +Εκτός από πεδία βασικού τύπου μπορούμε να έχουμε και πεδία κλάσεων των οποίων ο τύπος περιγράφεται από κλάσεις. Παράδειγμα μιας τέτοια κλάσης είναι το ορθογώνιο παραλληλεπίπεδο - κυβοειδές (κλάση Cuboid) το οποίο έχει ένα πεδίο τύπου Rectangle που ορίσαμε παραπάνω. 
 +
 +<code cpp Cuboid.hpp>
 +#include <iostream>
 +using namespace std;
 +
 +#include "Rectangle.hpp"
 +
 +class Cuboid {
 +  private:
 +    int length;
 +    Rectangle rect;
 +  public:
 +    void setRectangle(Rectangle r);
 +    Rectangle getRectangle() const;
 +    void setLength(int l);
 +    int getLength() const;
 +    int volume();
 +};
 +</code>
 +
 +<code cpp Cuboid.cpp>
 +#include "Cuboid.hpp"
 +
 +void Cuboid::setRectangle(Rectangle r) {rect = r;}
 +Rectangle Cuboid::getRectangle() const {return rect;}
 +void Cuboid::setLength(int l) { length = l; }
 +int Cuboid::getLength() const { return length; }
 +
 +int Cuboid::volume() {
 +  return length * rect.getWidth() * rect.getHeight();
 +}
 +</code>
cpp/classes.txt · Last modified: 2021/05/06 23:01 (external edit)