Στην συνέχεια δημιουργώ μιά κλάση που κάνει την δουλεία του προηγουμένου
προγράμματος + κάτι επιπλέον. Συγκεκριμένα, εκτός του ονόματος, που δια
χειρίζεται η μητέρα κλάση η HelloAge: α) ζητά από τον χρήστη την ηλικία του
β) τυπώνει μήνυμα με κάποια στοιχεία σχετικά με την ηλικία του.
Για ευκολία παραθέτω και τον κώδικα της παλιάς κλάσης Hello.
class Hello { private: char name[200]; bool finish; public: Hello() {finish = false;} virtual ~Hello(){} bool GetFinishValue() {return finish;} void GetNameFromUser(); void PrintMessage(); void AskFinish(); }; class HelloAge : public Hello { private: int age; public: HelloAge(){age=0;} virtual ~HelloAge(){} void GetAgeFromUser(); void PrintAgeMessage(); };
class HelloAge : public Hello | Δήλωση της κλάσης HelloAge ως υποκλάσης της Hello. Το public σημαίνει ότι η HelloAge Είναι μιά κλάση Hello αλλά και κάτι επιπλέον. |
int age; | Η μία και μοναδική μεταβλητή της κλάσης, ένας ακέραιος όπου θα τοποθετηθεί η ηλικία του χρήστη. Η υποκλάση δεν έχει πρόσβαση στις μεταβλητές της μητέρας κλάσης (Hello) διότι αυτές έχουν ορισθεί ως private. |
HelloAge(){age=0;} | Ο κύριος κατασκευαστής (constructor) της κλάσης, που κατά την δημιουργία της θέτει την μεταβλητή age=0, σε πιό πολύπλοκες κλάσεις μπορεί να γίνονται εδώ κάποιες προετοιμασίες γιά την χρήση της κλάσσης. Σημείωσε ότι κατά την δημιουργία της κλάσης καλήται πρώτα ο κατασκευαστής της μητέρας κλάσης και κατόπιν αυτός της υποκλάσης, εφόσον και οι δύο είναι public. |
virtual ~HelloAge(){} | Ο καταστροφέας (destructor) της κλάσης, που εδώ δεν κάνει τίποτε, αλλά σε πιό σύνθετες κλάσεις συνήθως απελευθερώνει μνήμη που χρησιμοποιεί η κλάση. Σημείωσε ότι πρώτα καλήται αυτός ο καταστροφέας και κατόπιν εκείνος της μητέρας κλάσης. Δηλαδή η σειρά κλήσης των καταστροφέων είναι αντίθετη της σειράς κλήσης των κατασκευαστών. |
void GetAgeFromUser(); | Μιά συνάρτηση η οποία θα ζητά από τον χρήστη την ηλικία του και θα την αποθηκεύει στην μεταβλητή age (κατασκευάζεται το σώμα της παρακάτω) |
void PrintAgeMessage(); | Μιά συνάρτηση που τυπώνει κάποιο μήνυμα (κατασκευάζεται το σώμα της παρακάτω) |
Τα παραπάνω μπλοκ αναγνωρίζονται από την C++ σαν ορισμοί μιάς κλάσης και μιάς υποκλάσης. Οι public συναρτήσεις της μητέρας μπορούν να κληθούν από την υποκλάση. Το δεύτερο μπλοκ είναι το interface της υποκλάσης. Περιέχει όλη την πληροφορία γιά το τι κάνει η κλάση. Το πως το κάνει αυτό που κάνει καθορίζεται από το σώμα των διαφόρων συναρτήσεων οι οποίες συνολικά αποτελούν (με τα σώματά τους) την implementation (υλοποίηση) της κλάσης. Στην συγκεκριμένη περίπτωση η υλοποίηση (της παλιάς και της νέας κλάσης) είναι η εξής:
void Hello::GetNameFromUser() { cout << "Write your name:\n" << endl; cin >> name ; } void Hello::PrintMessage() { cout <<"\n ********* Hello " << name << " Welcome to C++ ********\n\n" << endl; } void Hello::AskFinish() { char response[10]; cout << "Finish?...Yes(Y) ... No(N)....\n" << endl; cin >> response ; finish = (response[0]=='Y' || response[0]=='y'); }
void HelloAge::GetAgeFromUser() { cout << "How old are you?\n" << endl ; cin >> age ; } void HelloAge::PrintAgeMessage() { int weeks = age*48; int months = age*12; int days = age*365; int hours = days*24; cout << "You live " << age << " years \n" << months << " months at least,\n " << weeks << " weeks at least,\n " << days <<" days at least \n" << hours << " hours at least!" << endl; }Βλέπουμε ότι στην υλοποίηση ορίζεται το σώμα των συναρτήσεων (member functions) της κλάσης. Η C++ αναγνωρίζει ότι πρόκειται για μέλη της κλάσης HelloAge από την προσθήκη του HelloAge:: μπροστά από κάθε συνάρτηση.
Interface, δημιουργούμε αρχείο κειμένου με όνομα HelloClass.h το οποίο περιέχει:
#ifndef HELLOCLASS #define HELLOCLASS class Hello { private: char name[200]; bool finish; public: Hello() {finish = false;} virtual ~Hello(){} bool GetFinishValue() {return finish;} void GetNameFromUser(); void PrintMessage(); void AskFinish(); }; #endif // HELLOCLASS
Δημιουργούμε επίσης αρχείο κειμένου με όνομα HelloAgeClass.h το οποίο περιέχει τον κώδικα.
#ifndef HELLOAGECLASS #define HELLOAGECLASS #include "Hello.h" class HelloAge : public Hello { private: int age; public: HelloAge(){age=0;} virtual ~HelloAge(){} void GetAgeFromUser(); void PrintAgeMessage(); }; #endif // HELLOAGECLASSΣημείωσε την εντολή συμπερίληψης
#include "Hello.h"στην αρχή του αρχείου. Αυτή εξασφαλίζει την διασύνδεση με την μητέρα κλάση. Αν δεν βάζαμε αυτή την εντολή, ο μεταφραστής θα έδινε μήνυμα λάθους, αναφέροντάς μας ότι δεν του είναι γνωστή καμμία κλάση Hello.
Impementation, δημιουργούμε αρχείο κειμένου με όνομα HelloClass.cpp το οποίο περιέχει:
#include <iostream.h> #include <HelloClass.h> void Hello::GetNameFromUser() { cout << "Write your name:\n" << endl; cin >> name ; } void Hello::PrintMessage() { cout <<"\n ********* Hello " << name << " Welcome to C++ ********\n\n" << endl; } void Hello::AskFinish() { char response[10]; cout << "Finish?...Yes(Y) ... No(N)....\n" << endl; cin >> response ; finish = (response[0]=='Y' || response[0]=='y'); }Δημιουργούμε επίσης αρχείο κειμένου με όνομα HelloAgeClass.cpp το οποίο περιέχει:
#include <iostream.h> #include <HelloAgeClass.h> void HelloAge::GetAgeFromUser() { cout << "How old are you?\n" << endl ; cin >> age ; } void HelloAge::PrintAgeMessage() { int weeks = age*48; int months = age*12; int days = age*365; int hours = days*24; cout << "You live " << age << " years \n" << months << " months at least,\n " << weeks << " weeks at least,\n " << days <<" days at least \n" << hours << " hours at least!" << endl; }
#include <stdio.h> #include "HelloClass.h" #include "HelloAgeClass.h" int main(int argc, char* argv[]) { HelloAge h ; while(h.GetFinishValue()==false) { h.GetNameFromUser(); h.PrintMessage(); h.GetAgeFromUser(); h.PrintAgeMessage(); h.AskFinish(); } return 0; }
#include <stdio.h> | Εντολή συμπερίληψης βασικής βιβλιοθήκης της C++ |
#include "HelloClass.h" #include "HelloAgeClass.h" | Εντολή συμπερίληψης των αρχείων interface της κλάσης/υποκλάσης που θα χρησιμοποιήσω |
HelloAge h; | Ορισμός μιάς μεταβλητής (h) τύπου HelloAge. Η h λέγεται και στιγμιότυπο (instance) της κλάσης HelloAge. Σημείωσε ότι αμέσως μετά τον ορισμό ο compiler εκτελεί τον κατασκευαστή (constructor) της Hello (μητέρας κλάσης), σύμφωνα με τον οποίο (δες πιο πάνω) η τιμή της finish ορίζεται false. Κατόπιν εκτελεί τον κατασκευαστή της HelloAge, σύμφωνα με τον οποίο η τιμή της age ορίζεται ίση με 0. |
while(h.GetFinishValue()==false) | Μιά σύνθετη εντολή. Η εντολή while στέκεται στην κεφαλή του βρόγχου και εξετάζει την τιμή της μεταβλητής finish της κλάσης. Την τιμή αυτή την παίρνουμε με την συνάρτηση h.GetFinishValue() και την συγκρίνουμε με την false. Ο βρόγχος συνεχίζει να λειτουργεί εφ΄όσον η τιμή της finish είναι false. Σημείωσε ότι η h παρόλο που είναι μεταβλητή τύπου HelloAge χρησιμοποίεί αυτήν την συνάρτηση της μητέρας κλάσης Hello. Το ίδιο συμβαίνει και με τις άλλες public συναρτήσεις της Hello παρακάτω. |
h.GetNameFromUser(); | Η συνάρτηση που παίρνει από τον χρήστη το όνομα και το αποθηκεύει στην μεταβλητή name |
h.PrintMessage(); | Η συνάρτηση που τυπώνει ένα μήνυμα και το όνομα που έδωσε ο χρήστης |
h.GetAgeFromUser(); |
Η συνάρτηση που παίρνει από τον χρήστη την ηλικία και την αποθηκεύει
στην μεταβλητή age. Τούτη είναι συνάρτηση της HelloAge και όχι της μητέρας
κλάσης Hello. Αν είχαμε ανακοινώση την μεταβλητή h με την εντολή
Hello h ;αντί της HelloAge h ;, θα είχαμε κάνει σφάλμα και κατά την εκτέλεση της h.GetAgeFromUser();ο μεταφραστής θα έβγαζε μήνυμα λάθους, δηλώνοντας ότι η κλάση Hello δεν έχει καμμία συνάρτηση GetAgeFromUser. |
h.PrintAgeMessage(); | Η συνάρτηση που τυπώνει ένα μήνυμα σχετικό με την ηλικία που έδωσε ο χρήστης. Και εδώ ισχύει η παρατήρηση της προηγούμενης εντολής. |
h.AskFinish(); |
Η συνάρτηση που ζητά από τον χρήστη αν θα συνεχίσει ή όχι, και ανάλογα με την
απάντηση δίδει τιμή στην finish. Σημείωσε εδώ ότι αν η finish ήταν public,
θα ήταν σωστή η εντολή if(h.finish==true) { ...αλλες εντλολές ... } |
Η τελεία h. | Καθορίζει ότι οι συναρτήσεις που χρησιμοποιούμε είναι μέλη (member-functions) της κλάσης στην οποία ανήκει η μεταβλητή h |