Αντικειμενοστρεφής προγραμματισμός στη C: Διαφορά μεταξύ των αναθεωρήσεων
Περιεχόμενο που διαγράφηκε Περιεχόμενο που προστέθηκε
μ σύνδεσμοι |
|||
Γραμμή 1:
Η βασική διαφορά του [[Αντικειμενοστρεφής προγραμματισμός|αντικειμενοστρεφούς προγραμματισμού]] από τον [[Διαδικαστικός προγραμματισμός|διαδικαστικό προγραμματισμό]] είναι η συσχέτιση των [[Δεδομένα|δεδομένων]] με τις λειτουργίες που μπορούν να
δεχθούν/πραγματοποιήσουν. Η συσχέτιση αυτή πραγματοποιείται με μία από τις βασικές μονάδες του αντικειμενοστρεφούς προγραμματισμού, την ''κλάση''. ▼
▲δεχθούν/πραγματοποιήσουν. Η συσχέτιση αυτή πραγματοποιείται με μία από τις βασικές
Αν και η [[γλώσσα προγραμματισμού]] [[C
▲Αν και η γλώσσα C είναι μία πολύ δυνατή γλώσσα, με αυξημένη δυνατότητα ελέγχου του υλικού και των παραμέτρων αυτού, δεν είναι αντικειμενοστρεφής. Εντούτοις, και με την χρήση των δυνατοτήτων της γλώσσας, μπορεί να προσομοιωθεί η λειτουργικότητα
Σε αυτό το άρθρο, θα παρουσιαστούν οι τρόποι με τους οποίους μπορούν να προσομοιωθούν οι εξής λειτουργίες:
* Κληρονομικότητα
* [[Πολυμορφισμός]]
* Πρότυπα
Μέσα από τις προαναφερθείσες λειτουργίες θα αναδειχθούν οι τρόποι και οι δυνατότητες της γλώσσας C με τους οποίους μπορεί να προσομοιώσει τις
==Πολυμορφισμός στην C==
Ο πολυμορφισμός είναι μία από τις πιο σημαντικές έννοιες στον αντικειμενοστρεφή προγραμματισμό. Αν κοιτάξουμε όλα τα αρχικά πρότυπα σχεδίασης, σχεδόν όλα τους, χρησιμοποιούν τον πολυμορφισμό και τις ιδιότητές του.
===Μέθοδοι Constructor και Destructor===
Στην [[C++]], οι δύο αυτές μέθοδοι είναι κάποιες ειδικές μέθοδοι που καλούνται όταν ένα αντικείμενο δημιουργείται ή καταστρέφεται αντιστοίχως. Ο χειριστής new κατανέμει την μνήμη για την κλάση και μετά καλεί τον κατασκευαστή (Constructor) της κλάσης αυτής. Αντίστοιχα, ο χειριστής delete καλεί πρώτα τον Destructor της κλάσης και μετά αποδεσμεύει την μνήμη που χρησιμοποιούσε η κλάση.
===Διάταξη μνήμης ενός αντικειμένου===
Στην C
Στην C++, όταν δημιουργείται ένα αντικείμενο, κατανέμεται μνήμη μόνο για τα δεδομένα της κλάσης. Υπάρχει μόνο ένα αντίγραφο των μεθόδων μελών και διαμοιράζονται σε όλα τα στιγμιότυπα της κλάσης.
Στην C, για να υλοποιήσουμε αυτή την συμπεριφορά, δημιουργούμε όλες τις μεθόδους
Στην C++, μόνο ένα αντίγραφο των μεθόδων μελών υπάρχει στην μνήμη και για να διακρίνουμε τα στιγμιότυπα των κλάσεων μεταξύ τους, χρησιμοποιούμε τον δείκτη this, ο οποίος δείχνει κάθε στιγμή στο στιγμιότυπο που δημιουργήθηκε. Οι μέθοδοι χρησιμοποιούν τον δείκτη this για να αποκτούν πρόσβαση στα δεδομένα. Εσωτερικά, η διεύθυνση στον δείκτη this δίνεται στις μεθόδους μέλη μέσα από τον [[καταχωρητής|καταχωρητή]] ecx του [[μικροεπεξεργαστής|μικροεπεξεργαστή]].
Στην C, για να υλοποιήσουμε τον δείκτη this, δηλώνουμε μία μεταβλητή global integer που ονομάζουμε ECX. Πριν καλέσουμε οποιαδήποτε μέθοδο, η μεταβλητή ECX θα τεθεί ώστε να δείχνει στην διεύθυνση μνήμης που χρησιμοποιεί η δομή δεδομένων μας. Όλες οι μέθοδοι χρησιμοποιούν, έτσι, την μεταβλητή ECX ώστε να αποκτήσουν πρόσβαση στα μέλη της δομής.
===Εικονικός πίνακας και δείκτης εικονικού πίνακα===
Στην C++, κάθε κλάση που έχει τουλάχιστον μία εικονική μέθοδο, θα έχει έναν σχετικό εικονικό πίνακα. Δεν πρόκειται για τίποτα άλλο παρά για ένα πίνακα με δείκτες μεθόδων. Αυτός ο πίνακας για μία κλάση περιέχει τις διευθύνσεις των εικονικών μεθόδων που περιέχονται στην κλάση καθώς και τις διευθύνσεις των εικονικών μεθόδων που κληρονομεί η κλάση. Στην περίπτωση των κληρονομούμενων μεθόδων, λαμβάνονται υπ' όψιν μόνο αυτές που δεν υπερκαλύπτονται. (Function Override)
Η σειρά με την οποία συμπληρώνεται ο εικονικός πίνακας έχει ως εξής:
Γραμμή 42 ⟶ 39 :
#Οι διευθύνσεις των νέων εικονικών μεθόδων που δηλώνονται στην κλάση προστίθεται, βάσει της σειράς δήλωσης.
Στην C, θα υλοποιήσουμε τις εικονικές μεθόδους ως global πίνακες
Ο εικονικός πίνακας για την κλάση X θα περιέχει τις διευθύνσεις του Destructor και τις διευθύνσεις των τριών εικονικών μεθόδων.
Γραμμή 124 ⟶ 121 :
===Παράδειγμα===
Θα δημιουργήσουμε μία κλάση "Point" η οποία αντιπροσωπεύει ένα σημείο στο δισδιάστατο χώρο. Η κλάση αυτή θα περιέχει δύο ακέραιες μεταβλητές, οι οποίες αντιπροσωπεύουν τις συντεταγμένες του σημείου. Θα παρέχουμε επίσης τη δυνατότητα δημιουργίας και καταστροφής του αντικειμένου καθώς επίσης και τη δυνατότητα μετακίνησής του. Θέλουμε επίσης και την κλάση "Circle" η οποία θα αντιπροσωπεύει ένα κύκλο. Η κλάση αυτή θα αποτελείται απ ο ένα σημείο καθώς επίσης και μία επιπλέον μεταβλητή η οποία θα αποτελεί την ακτίνα του κύκλου και η κλάση αυτή θα παρέχει μία μέθοδο δημιουργίας και διαγραφής καθώς επίσης και μία μέθοδο μετακίνησης.
====Η κλάση "Class"====
Θέλουμε να κατασκευάσουμε την κλάση "Point" με τέτοιο τρόπο ώστε η κλάση "Circle" να μπορεί να κληρονομήσει απ ο αυτή. Κάθε κλάση στον αντικειμενοστραφή προγραμματισμό έχει κάποια κοινά χαρακτηριστικά με τις υπόλοιπες κλάσεις (κάθε κλάση έχει ένα κατασκευαστή), για να διατηρήσουμε μία συνοχή με τις αντικειμενοστραφής γλώσσες θα πρέπει να παρέχουμε μία παρόμοια διεπαφή. Καθώς το να παρέχουμε ένα γενικό τρόπο κατασκευής και δημιουργίας αντικειμένων προσθέτει αρκετά προβλήματα, κάνει τον κώδικα επιρρεπή σε λάθη και περιορίζει τις δυνατότητες θα πρέπει το κάθε αντικείμενο να γνωρίζει τη πόρους χρειάζεται καθώς και πώς να τους ελευθερώσει. Έτσι μπορούμε να χρησιμοποιούμε τη γενική συνάρτηση "new()" η οποία θα αναλαμβάνει να δημιουργεί τα αντικείμενα και η συνάρτηση "delete()" η οποία θα καταστρέφει το αντικείμενο.
Γραμμή 150 ⟶ 148 :
}
</source>
Η συνάρτηση "new()" δημιουργεί το νέο αντικείμενο και επιστρέφει ένα δείκτη σε αυτό. Μετά τη δημιουργία του αντικειμένου η μεταβλητή "p" δείχνει στο νέο αντικείμενο και ο δείκτης "class" του αντικειμένου "δείχνει" στην αρχή του αντικειμένου. Εάν υπάρχει κατασκευαστής για το αντικείμενο τότε καλούμε τον κατασκευαστή και επιστρέφουμε το αποτέλεσμά του, δηλαδή το νέο αντικείμενο.
Η συνάρτηση "delete()" διαγράφει το αντικείμενο καλώντας τη συνάρτηση καταστροφής του αντικειμένου, η οποία είναι υπεύθυνη για την απελευθέρωση τον πόρων που έχει δεσμεύσει.
Γραμμή 161:
}
</source>
====Η κλάση "Point"====
Μπορούμε να χρησιμοποιήσουμε την κλάση "Class" προσθέτοντας ένα δείκτη προς τη μέθοδο void (* draw) (const void * self) η οποία θα σχεδιάζει το σημείο.
Γραμμή 182 ⟶ 183 :
</source>
Η συνάρτηση "move()" δεν χρειάζεται να "συνδεθεί" με την κλάση καθώς η μεταφορά του σημείου και του κύκλου είναι ίδια καθώς ο κύκλος αποτελείται από ένα σημείο και την ακτίνα.
====Η κλάση "Circle"====
Η κλάση "Circle" αποτελείται απ ο ένα σημείο και την ακτίνα άρα η κλάση "Circle" γίνεται:
Γραμμή 207 ⟶ 209 :
Τα πρότυπα είναι μία αρκετά εύχρηστη λειτουργία των αντικειμενοστρεφών γλωσσών με την οποία μπορούν να δημιουργηθούν αλγόριθμοι και αφηρημένες μέθοδοι για να προσδιοριστούν έπειτα αναλόγως με τους τύπους δεδομένων που θα συσχετιστούν.
Εν γένει, τα πρότυπα είναι λειτουργία [[μεταπρογραμματισμός|μεταπρογραμματισμού]] (metaprogramming)<ref name="metaprogramming">[http://en.wikipedia.org/wiki/Metaprogramming Metaprogramming]</ref>, χρησιμοποιούμενη από αρκετές γλώσσες μεταξύ των οποίων και η C++, με την οποία επιτρέπεται η δημιουργία ενός γενικού αλγόριθμου ο οποίος μπορεί να χρησιμοποιηθεί όταν συσχετιστεί με κάποιο τύπο δεδομένων και για οποιοδήποτε τύπο δεδομένων.
Η πιο συνηθισμένη χρήση των templates είναι για την υλοποίηση δομών δεδομένων(Containers) οι οποίες μπορούν να χρησιμοποιηθούν για οποιοδήποτε τύπο δεδομένων. Έτσι, ο προγραμματιστής μπορεί να χρησιμοποιήσει έτοιμο αλγόριθμο, όπως η λειτουργία μίας λίστας, με διαφορετικούς τύπους δεδομένων αρχικοποιώντας κάθε φορά την δομή αυτή με τον τύπο δεδομένων που επιθυμεί. Ένα παράδειγμα είναι η κλάση CAtlArray, της βιβλιοθήκης atlcoll.h, μέλος της γενικής βιβλιοθήκης
<source lang="C">
Γραμμή 225 ⟶ 227 :
===Πρότυπα στην C===
Στη C τα πρότυπα (templates), μπορούν να προσομοιωθούν με την χρήση των μακροεντολών (macros) που προσφέρει ο
Μία από τις πιο έντονες χρήσεις της προσομοίωσης των templates απαντάται στον κώδικα του [[Πυρήνας Linux|πυρήνα του Linux]], όπου έχουν υλοποιηθεί δομές όπως η λίστα, η ούρα κτλ., και μπορεί να βρεθεί στην βιβλιοθήκη sys/sys/queue.h<ref name="queue"?[http://fxr.watson.org/fxr/source/sys/queue.h ]</ref>.
Αντιγράφοντας από τον προαναφερθέντα κώδικα μπορεί κανείς να παρατηρήσει
<source lang="C">
Γραμμή 254 ⟶ 256 :
</source>
Έτσι
Το ίδιο μπορεί να γίνει και για την λειτουργικότητα που μπορεί να προσφέρει μία λίστα. Π.χ.,
Γραμμή 265 ⟶ 267 :
(var) = SLIST_NEXT((var), field))
</source>
Όπου, και πάλι, μπορεί να φανεί η διαχείριση του κειμένου από τον prepocessor για την παραγωγή κώδικα και την προσομοίωση της λειτουργικότητας των προτύπων. Έτσι, για
#θα αποδώσει την διεύθυνση μνήμης της κεφαλής της λίστας στην μεταβλητή ,
#θα ελέγξει εάν η τιμή είναι NULL
#στην επανάληψη θα αποδώσει στην μεταβλητή var την τιμή του επόμενου
==Παραπομπές==
<references/>
|