Αντικειμενοστρεφής προγραμματισμός στη C: Διαφορά μεταξύ των αναθεωρήσεων

Περιεχόμενο που διαγράφηκε Περιεχόμενο που προστέθηκε
μ σύνδεσμοι
στοίχιση κώδικα
Γραμμή 55:
<source lang="C">
class Person
{
private:
char* pFirstName;
char* pLastName;
public:
Person(const char* pFirstName, const char* pLastName);
~Person();
 
void displayInfo();
void writeToFile(const char* pFileName);
};
</source>
Για να αναπαραστήσουμε την κλάση "Person" στη γλώσσα C θα χρησιμοποιήσουμε δομές, και συναρτήσεις που επιδρούν πάνω τους. Για παράδειγμα η κλάση "Person" θα μπορούσε να γραφεί στη γλώσσα C ως εξής<ref>Object Oriented Programming with ANSI-C</ref>:
<source lang="C">
typedef struct _Person Person;
 
typedef void (*fptrDisplayInfo)(Person*);
typedef void (*fptrWriteToFile)( Person*, const char*);
typedef void (*fptrDelete)( Person *) ;
 
typedef struct _Person
{
char* pFName;
char* pLName;
fptrDisplayInfo Display;
fptrWriteToFile WriteToFile;
fptrDelete Delete;
}Person;
 
person* new_Person(const char* const pFirstName, const char* const pLastName);
void const chardelete_Person(Person* const pLastNamepPersonObj);
void delete_Person(Person* const pPersonObj);
 
void Person_DisplayInfo(Person* const pPersonObj);
void Person_WriteToFile(Person* const pPersonObj, const char* pFileName);
</source>
Γραμμή 101 ⟶ 100 :
<source lang="C">
struct base
{
{
/* base class members */
};
 
struct derived
{
{
struct base super;
/* derived class members */
};
 
struct derived d;
struct base *base_ptr = (struct base *)&d; // upcast
struct derived derived_ptr = (struct derived *)base_ptr; // downcast
</source>
Γραμμή 125 ⟶ 124 :
Θέλουμε να κατασκευάσουμε την κλάση "Point" με τέτοιο τρόπο ώστε η κλάση "Circle" να μπορεί να κληρονομήσει απ ο αυτή. Κάθε κλάση στον αντικειμενοστραφή προγραμματισμό έχει κάποια κοινά χαρακτηριστικά με τις υπόλοιπες κλάσεις (κάθε κλάση έχει ένα κατασκευαστή), για να διατηρήσουμε μία συνοχή με τις αντικειμενοστραφής γλώσσες θα πρέπει να παρέχουμε μία παρόμοια διεπαφή. Καθώς το να παρέχουμε ένα γενικό τρόπο κατασκευής και δημιουργίας αντικειμένων προσθέτει αρκετά προβλήματα, κάνει τον κώδικα επιρρεπή σε λάθη και περιορίζει τις δυνατότητες θα πρέπει το κάθε αντικείμενο να γνωρίζει τη πόρους χρειάζεται καθώς και πώς να τους ελευθερώσει. Έτσι μπορούμε να χρησιμοποιούμε τη γενική συνάρτηση "new()" η οποία θα αναλαμβάνει να δημιουργεί τα αντικείμενα και η συνάρτηση "delete()" η οποία θα καταστρέφει το αντικείμενο.
<source lang="C">
struct Class {
size_t size;
void * (* ctor) (void * self, va_list * app);
void * (* dtor) (void * self);
};
</source>
Η μεταβλητή "size" περιέχει το μέγεθος το οποίο θα δεσμεύσει η "new()" για το αντικείμενο, "ctor" είναι η συνάρτηση δημιουργίας του αντικειμένου η οποία λαμβάνει σαν είσοδο τη μνήμη που έχει δεσμεύσει η "new()" καθώς και επιπλέον ορίσματα για την αρχικοποίηση των μεταβλητών, "dtor" είναι η συνάρτηση καταστροφής ενός αντικειμένου οι οποία δέχεται το αντικείμενο προς διαγραφή.
<source lang="C">
void * new (const void * _class, ...){
const struct Class * class = _class;
void * p = calloc(1, class -> size);
assert(p);
* (const struct Class **) p = class;
if (class -> ctor){
va_list ap;
va_start(ap, _class);
p = class -> ctor(p, & ap);
va_end(ap);
}
}
return p;
}
}
</source>
 
Γραμμή 154 ⟶ 153 :
<source lang="C">
void delete (void * self){
const struct Class ** cp = self;
if (self && * cp && (* cp) -> dtor)
self = (* cp) -> dtor(self);
free(self);
}
}
</source>
 
Γραμμή 165 ⟶ 164 :
Μπορούμε να χρησιμοποιήσουμε την κλάση "Class" προσθέτοντας ένα δείκτη προς τη μέθοδο void (* draw) (const void * self) η οποία θα σχεδιάζει το σημείο.
<source lang="C">
struct Point {
const void * class;
int x, y; /* coordinates */
};
static void * Point_ctor (void * _self, va_list * app){
struct Point * self = _self;
self -> x = va_arg(* app, int);
self -> y = va_arg(* app, int);
return self;
}
}
static void Point_draw (const void * _self){
const struct Point * self = _self;
printf("Draw point at (%d,%d)", self -> x, self -> y);
}
}
</source>
Η συνάρτηση "move()" δεν χρειάζεται να "συνδεθεί" με την κλάση καθώς η μεταφορά του σημείου και του κύκλου είναι ίδια καθώς ο κύκλος αποτελείται από ένα σημείο και την ακτίνα.
Γραμμή 187 ⟶ 186 :
Η κλάση "Circle" αποτελείται απ ο ένα σημείο και την ακτίνα άρα η κλάση "Circle" γίνεται:
<source lang="C">
stuct Circle{
const struct Point _p;
int rad;
};
static void * Circle_ctor (void * _self, va_list * app){
struct Point * self = _self;
self -> x = va_arg(* app, int);
self -> y = va_arg(* app, int);
self -> rad = va_arg(* app, int);
return self;
}
}
static void Point_draw (const void * _self){
printf("Draw circle at (%d,%d) with radius %d\n",
self -> x, self -> y, self -> rad);
}
}
</source>
 
Γραμμή 214 ⟶ 213 :
<source lang="C">
CAtlArray<int> myTestArray;
int theElement;
int maxSizeOfArray = 100;
for (theElement = 0; theElement < maxSizeOfArray; theElement++)
{
myTestArray.add(theElement);
}
\end{lstlisting}
}
</source>
Γραμμή 234 ⟶ 231 :
 
<source lang="C">
/*
* Singly-linked List declarations.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head)\ { NULL }
{ NULL }
#define SLIST_ENTRY(type) \
(var); struct { \
struct {\
struct type *sle_next; /* next element */ \
}
</source>
Έτσι, εάν είναι επιθυμητή η δημιουργία μίας λίστας με τύπους int, τότε μπορεί να κανείς να γράψει:
<source lang="C">
SLIST_HEAD(myListHead, int) myHead = SLIST_HEAD_INITIALIZER(myHead);
</source>
Γραμμή 260 ⟶ 256 :
Το ίδιο μπορεί να γίνει και για την λειτουργικότητα που μπορεί να προσφέρει μία λίστα. Π.χ.,
<source lang="C">
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST((head)); (var); (var) = SLIST_NEXT((var), \field))
(var); \
(var) = SLIST_NEXT((var), field))
</source>
Όπου, και πάλι, μπορεί να φανεί η διαχείριση του κειμένου από τον prepocessor για την παραγωγή κώδικα και την προσομοίωση της λειτουργικότητας των προτύπων. Έτσι, για τη λειτουργία foreach ο προεπεξεργαστής: