Pages

Wednesday, October 13, 2010

C++ 101: The Basics

Θα ξεφύγω λίγο από php/js κλπ και θα ασχοληθώ λίγο με τη C++ και την αντικειμενοστρέφεια γενικότερα.


Η έννοια της αντικειμενοστρέφειας έχει καλυφτεί και σε παλιότερο post και είναι η ίδια, αλλά θα τα αναφέρω κι εγώ just to make sure.


Στην C υπήρχαν τα structs τα οποία ήταν μια "ομάδα" μεταβλητών.
Μπορούμε ας πούμε να κάνουμε μια δομή Person στο οποίο θα περιέχεται ένα string για το όνομά του και ένας ακέραιος για την ηλικία του.
Με αυτό τον τρόπο μπορούμε να δημιουργήσουμε μια μεταβλητή τύπου Person και να κρατάμε αυτά τα στοιχεία μαζί.

Με ένα παράδειγμα ίσως είναι πιο κατανοητό:

#include <stdio.h>
#include <stdlib.h>

struct Person
{
    char name[20];
    int age;
};

void main() {

    struct Person person1;

    printf("Give person's name: ");
    scanf("%s", person1.name);
    printf("Give person's age: ");
    scanf("%d", &person1.age);

    printf("\n===========================\n");
    printf("The person's name is %s and the age is %d\n", person1.name, person1.age);



    system("pause");
}

Όπως βλέπουμε η πρόσβαση στις εσωτερικές μεταβλητές της Person γίνεται με την χρήση της τελείας (.) και κατά τα άλλα η χρήση γίνεται κανονικά όπως και αν ήταν ξεχωριστές μεταβλητές.


C++ εισαγωγή

Μια εύλογη απορία που μπορεί να έχει κάποιος σε αυτό το σημείο είναι πού είναι η C++ τόση ώρα;

Ο λόγος που ξεκίνησα από εδώ, είναι γιατί οι κλάσεις στην C++ μοιάζουν με structs, απλά έχουν μερικές επιπλέον ιδιότητες.

Πάμε όμως από την αρχή:

Η C++ είναι μια αντικειμενοστρεφής γλώσσα, όπως η Java.
Αυτό σημαίνει ότι πλέον θα έχουμε να κάνουμε με κλάσεις και με αντικείμενα κατά κύριο λόγο και λιγότερο με μεμονωμένες συναρτήσεις.

Τι είναι όμως η κλάση;

Για να απαντήσουμε σε αυτό ας κοιτάξουμε λίγο γύρω μας.
Ο καθένας από μας έχει μερικά διαφορετικά χαρακτηριστικά, όπως ύψος, χρώμα μαλλιών, χρώμα ματιών, ηλικία, όνομα κλπ.

Όλοι όμως έχουμε μαλλιά, μάτια, ηλικία, όνομα κλπ.

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

Η κλάση άνθρωπος προσδιορίζει ότι όλοι ανεξαιρέτως οι άνθρωποι θα έχουν ένα σύνολο ιδιοτήτων.

Αυτό εκφράζεται προγραμματιστικά ως εξής:


#include <iostream>

using namespace std;

class Person
{
    public:
        char name[20];
        int age;
};

int main()
{
    Person a;

    cout<<"What's your name? ";
    cin>>a.name;
    cout<<"What's your age? ";
    cin>>a.age;

    cout<<"============================"<<endl;
    cout<<"Your name is: "<<a.name<<"\nAnd your age is: "<<a.age<<endl;


    return 0;
}


Εδώ είναι ουσιαστικά το προηγούμενο πρόγραμμα γραμμένο the C++ way, δλδ με κλάσεις και με τα "καινούρια" χαρακτηριστικά που μας δίνει η C++.

Οι διαφορές

  • Αντί για stdio.h χρησιμοποιούμε iostream:
    Το iostream είναι μια κλάση για να χειρίζεται το "ρεύμα" εισόδου/εξόδου (Input/Output Stream). Αμέσως μετά βλέπουμε την εντολή που θα χρησιμοποιούμε σχεδόν πάντα: using namespace std η εξήγηση της οποίας ξεφεύγει από "τα βασικά" και μπορείτε όσοι ενδιαφέρεστε να τη βρείτε στα παρακάτω links:
    http://www.cplusplus.com/doc/tutorial/program_structure/
    http://www.cplusplus.com/doc/tutorial/namespaces/
  • Αντι για χρήση struct κάνουμε χρήση class. Όπως είπαμε και νωρίτερα η κλάση είναι ο τρόπος για να παράγουμε αντικείμενα. Όπως και στα structs, έτσι κι εδώ, περιγράφουμε από τι θα αποτελείται το κάθε αντικείμενο. Η λέξη public που ακολουθεί σημαίνει ότι οι μεταβλητές μας θα είναι προσβάσιμες από οποιοδήποτε μέρος του προγράμματός μας. Εδώ να σημειώσω ότι στο 95% των περιπτώσεων, οι μεταβλητές στις κλάσεις ΔΕΝ θα θέλουμε να είναι προσβάσιμες από το υπόλοιπο πρόγραμμα, οπότε αντί για public θα χρησιμοποιούμε την λέξη private
  • Μέσα στη main βλέπουμε ότι αντί για τα κλασσικά printf() και scanf() χρησιμοποιούμε τα (πολύ καλύτερα και πιο 'έξυπνα' ) cout και cin αντίστοιχα. Η σύνταξή τους είναι αυτή που φαίνεται, όπως φαίνεται :P
    Στο cout ισχύουν τα \n για αλλαγή γραμμής, \t για να βάζουμε tab κ.ο.κ. Επίσης όπως βλέπετε, για αλλαγή γραμμής υπάρχει και η δυνατότητα να χρησιμοποιήσετε το endl
    Στο cin τα πράγματα είναι πολύ απλούστερα συγκριτικά με την scanf(). Απλά βάζεις τη μεταβλητή που θες και καταλαβαίνει μόνο του τι να κάνει, χωρίς να απαιτεί & ή προσδιοριστικά για τον τύπο της μεταβλητής κλπ.

Και γιατί δηλαδή να χρησιμοποιήσουμε class αντί για structs;

Γιατί με τις κλάσεις μας δίνεται η δυνατότητα να έχουμε μαζί με τις μεταβλητές του κάθε αντικειμένου και τις συναρτήσεις που το αφορούν.

Setters και Getters

Ανέφερα πριν ότι στο 95% των περιπτώσεων οι μεταβλητές των αντικειμένων μας θα είναι δηλωμένες ως private. Ο τρόπος να έχουμε πρόσβαση στις μεταβλητές αυτές είναι μέσω συναρτήσεων που είναι γνωστές ως setters και getters.
Όπως φαίνεται και από το όνομά τους, οι setters είναι υπεύθυνες να δίνουν τιμές στις μεταβλητές του αντικειμένου μας, ενώ οι getters χρησιμοποιούνται για την ανάκτηση των τιμών τους.

Ακολουθεί παράδειγμα με χρήση setters και getters συναρτήσεων:

#include <iostream>
#include <cstring>

using namespace std;

class Person
{
    private:
        char name[20];
        int age;


    public:
        void setName(char* newName)
        {
            strcpy(name, newName);
        }
        void setAge(int newAge)
        {
            age = newAge;
        }


        char* getName()
        {
            return name;
        }
        int getAge()
        {
            return age;
        }
};

int main()
{
    Person a;
    char tempName[20];
    int tempAge;

    cout<<"What's your name? ";
    cin>>tempName;
    cout<<"What's your age? ";
    cin>>tempAge;

    //kaloume tous setters gia na ta steiloume sto antikeimeno:
    a.setName(tempName);
    a.setAge(tempAge);

    cout<<"============================"<<endl;
    cout<<"Your name is: "<<a.getName();
    cout<<"\nAnd your age is: "<<a.getAge()<<endl;


    return 0;
}



Πάω στοίχημα ότι τώρα το βρίσκετε χαζό να γράφετε τόσο παραπάνω κώδικα ενώ μπορούσατε να το κάνετε και με τον προηγούμενο -απλούστερο- τρόπο. Αρκεστείτε προς το παρόν απλά στο εξής:
"Έτσι είναι το σωστό". Στα παρακάτω "επεισόδια" θα καταλάβετε περισσότερο τι εννοώ και ποια η σημασία του να γράφεις έτσι τον κώδικα.

Στο επόμενο επεισόδιο:
Συναρτήσεις εγκατάστασης (constructors), o δείκτης this, και η κλάση string.

Ερωτήσεις, σχόλια, και προτάσεις ευπρόσδεκτα.

No comments:

Post a Comment