User Tools

Site Tools


cpp:constructors

Κατασκευαστές της κλάσης

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

Rectangle.hpp
#include <iostream>
using namespace std;
 
class Rectangle {
  private:
    int width, height;
  public:
    Rectangle(int w, int h);
    void setWidth(int w);
    void setHeight(int h);
    int getWidth() const;
    int getHeight() const;
};
Rectangle.cpp
#include "Rectangle.hpp"
 
Rectangle::Rectangle(int w, int h) {
  width = w; height = h;
}
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; }
RectangleUsage.cpp
#include "Rectangle.hpp"
 
int main () {
  Rectangle rect(5,6);
  cout << "area: " << rect.getWidth() * rect.getHeight() << endl;
  return 0;
}

Σε αναλογία με τις μεθόδους ο κατασκευαστής μπορεί να οριστεί εντός της κλάσης, όπως παρακάτω. Η δήλωση εντός της κλάσης συνεπάγεται τη δήλωση από τον προγραμματιστή του κατασκευαστή ως inline.

Rectangle.cpp
class Rectangle {
  private:
    int width, height;
  public:
    Rectangle(int w, int h){
      width = w; height = h;
    }
};

Μεταγλώττιση

Για την μεταγλώττιση αρκεί να μεταγλωττίσετε κάθε επιμέρους αρχείο κλάσης ξεχωριστά και στη συνέχεια να δημιουργήσετε το τελικό εκτελέσιμο. Στο συγκεκριμένο παράδειγμα, η διαδικασία είναι η παρακάτω και παράγει το εκτελέσιμο με όνομα a.out:

g++ -Wall -g Rectangle.cpp -c
g++ -Wall -g Rectangle.o RectangleUsage.cpp 

Default κατασκευαστής

Εάν δεν οριστεί κανένας κατασκευαστής σε μία κλάση τότε για την κλάση ορίζεται από τον μεταγλωττιστή ο default κατασκευαστής. Ο κατασκευαστής αυτός δεν έχει ορίσματα. Τα πεδία της κλάσης αρχικοποιούνται ως εξής:

  1. για πεδία που έχουν βασικού τύπους (int, double, char κλπ) οι τιμές είναι τυχαίες.
  2. για πεδία που περιγράφονται από κλάσεις καλείται ο default κατασκευαστής της εκάστοτε κλάσης.

Εάν έχετε δηλώσει τουλάχιστον ένα κατασκευαστή που δεν είναι ο default κατασκευαστής χωρίς παραμέτρους τότε ο compiler δεν κατασκευάζει αυτόματα τον default κατασκευαστή. Σε περίπτωση που ο default κατασκευαστής δεν δημιουργηθεί αυτόματα από τον compiler, λαμβάνετε μήνυμα λάθους κατά τη μεταγλώττιση.

Υπερφόρτωση κατασκευαστών

Σε αναλογία με την υπερφόρτωση συναρτήσεων η C++ υποστηρίζει και υπερφόρτωση κατασκευαστών. Συγκεκριμένα, μπορείτε να έχετε περισσότερους από έναν κατασκευαστές αρκεί αυτοί να έχουν διαφορετικό αριθμό ή τύπο ορισμάτων. Δείτε το παρακάτω παράδειγμα της κλάση Rectangle, όπου δίνονται δύο επιπλέον κατασκευαστές, ένας κατασκευαστής που λαμβάνει ένα κοινό όρισμα και για τις δύο διαστάσεις του παραλληλογράμμου δημιουργώντας ένα τετράγωνο και ένας κατασκευαστής χωρίς ορίσματα που αναθέτει τυχαίες τιμές στα μήκη των πλευρών του παραλληλογράμμου.

Rectangle.hpp
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
 
class Rectangle {
  private:
    int width, height;
  public:
    Rectangle(int w, int h);
    Rectangle(int s);
    Rectangle();
    void setWidth(int w);
    void setHeight(int h);
    int getWidth() const;
    int getHeight() const;
};
Rectangle.cpp
#include "Rectangle.hpp"
 
Rectangle::Rectangle(int w, int h) {
  width = w; height = h;
}
 
Rectangle::Rectangle(int s) {
  width = s; height = s;
}
 
Rectangle::Rectangle() {
  srand(time(NULL));
  width = rand() % 10 + 1; height = rand() % 10 + 1;
}
 
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; }
RectangleUsage.cpp
#include "Rectangle.hpp"
 
int main () {
  Rectangle rect(5,6);
  cout << "area: " << rect.getWidth() * rect.getHeight() << endl;
  return 0;
}

Χρήση member initialization list για την αρχικοποίηση των μελών της κλάσης

Παραπάνω συναντήσαμε τον κατασκευαστή με δύο ορίσματα

Rectangle::Rectangle(int w, int h) {
  width = w; height = h;
}

Αντί για την παραπάνω δήλωση θα μπορούσατε να γράψετε ισοδύναμα:

Rectangle::Rectangle(int w, int h) : width(w) {
  height = h;
}

ή ισοδύναμα

Rectangle::Rectangle(int w, int h) : width(w), height(h) {}

Ο παραπάνω τρόπος γραφής ονομάζεται στη βιβλιογραφία member initilization list. Τελικά η κλάση Rectangle μπορεί να γραφεί με χρήση member initilization list όπως παρακάτω:

Rectangle.hpp
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
 
class Rectangle {
  private:
    int width, height;
  public:
    Rectangle(int w, int h);
    Rectangle(int s);
    Rectangle();
    void setWidth(int w);
    void setHeight(int h);
    int getWidth() const;
    int getHeight() const;
};
Rectangle.cpp
#include "Rectangle.hpp"
 
Rectangle::Rectangle(int w, int h) : width(w), height(h) {
}
 
Rectangle::Rectangle(int s) : width(s), height(s) {
}
 
Rectangle::Rectangle() {
  srand(time(NULL));
  width = rand() % 10 + 1; height = rand() % 10 + 1;
}
 
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; }

Κλήση ενός κατασκευαστή μέσα από άλλο κατασκευαστή

Συχνά μπορεί να θέλουμε να καλέσουμε μέσα από ένα κατασκευαστή έναν άλλο κατασκευαστή. Μπορείτε να το κάνετε αυτό όπως καλείτε οποιαδήποτε άλλη μέθοδο. Στο προηγούμενο παράδειγμα, ο κατασκευαστής με τη μία παράμετρο καλεί εσωτερικά τον κατασκευαστή με τις δύο παραμέτρους ως εξής:

Rectangle::Rectangle(int s) {
  Rectangle(s,s);
}

Ο ίδιος κώδικας με χρήση member initialization list μπορεί να γραφεί ως εξής:

Rectangle::Rectangle(int s) : Rectangle(s,s) {
}

Αρχικοποίηση αντικειμένων που περιέχουν πεδία που περιγράφονται από κλάσεις

Στην προηγούμενη ενότητα είδαμε την κλάση Cuboid που περιγράφει την κλάση του κυβοειδούς και περιέχει ένα πεδίο τύπου Rectangle. Εδώ θα δούμε πως μπορούμε να ορίσουμε ένα ή περισσότερους κατασκευαστές για την κλάση του κυβοειδούς.

Cuboid.hpp
#include <iostream>
using namespace std;
 
#include "Rectangle.hpp"
 
class Cuboid {
  private:
    int length;
    Rectangle rect;
  public:
    Cuboid(int w, int h, int l);
    Cuboid(Rectangle r, int l);
 
    void setRectangle(Rectangle r);
    Rectangle getRectangle() const;
    void setLength(int l);
    int getLength() const;
    int volume();
};
Cuboid.cpp
#include "Cuboid.hpp"
 
Cuboid::Cuboid(int w, int h, int l)  {
  rect.setWidth(w);
  rect.setHeight(h);
  length = l;
}
 
Cuboid::Cuboid(Rectangle r, int l) {
   rect = r;
   length = l;
}
 
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();
}

Οι παραπάνω δύο κατασκευαστές με χρήση member initialιzation list μπορούν να γραφούν ως εξής:

Cuboid::Cuboid(Rectangle r, int l) : rect(r), length(l) { } 
Cuboid::Cuboid(int w, int h, int l) : rect(w,h), length(l) { }

Στον πρώτο κατασκευαστή με τα δύο ορίσματα γίνεται ανάθεση του αντικειμένου r στο πεδίο rect, αντιγράφοντας κάθε πεδίο της παραμέτρου r στο αντίστοιχο πεδίο του rect. Στον δεύτερο κατασκευαστή με τα τρία ορίσματα καλείται ο κατασκευαστής της κλάσης Rectangle με ορίσματα (w,h).

cpp/constructors.txt · Last modified: 2021/05/07 06:11 (external edit)