Come posso simulare il polimorfismo in stile OO in C?

C’è un modo per scrivere codice simile a OO nel linguaggio di programmazione C ?


Guarda anche:

  • Puoi scrivere codice orientato agli oggetti in C?
  • Orientamento all’object in C

Trovato cercando su “[c] oo”.

Il primo compilatore C ++ (“C con classi”) genererebbe effettivamente il codice C, quindi è sicuramente fattibile.

Fondamentalmente, la tua class base è una struct; le strutture derivate devono includere la struttura di base nella prima posizione, in modo che un puntatore alla struttura “derivata” sia anche un puntatore valido alla struttura di base.

 typedef struct { data member_x; } base; typedef struct { struct base; data member_y; } derived; void function_on_base(struct base * a); // here I can pass both pointers to derived and to base void function_on_derived(struct derived * b); // here I must pass a pointer to the derived class 

Le funzioni possono essere parte della struttura come puntatori di funzione, in modo che una syntax come p-> call (p) diventi ansible, ma è comunque necessario passare esplicitamente un puntatore alla struct alla funzione stessa.

L’approccio comune è definire la struttura con i puntatori alle funzioni. Questo definisce i “metodi” che possono essere chiamati su qualsiasi tipo. I sottotipi quindi impostano le proprie funzioni in questa struttura comune e lo restituiscono.

Ad esempio, nel kernel di Linux, c’è struct:

 struct inode_operations { int (*create) (struct inode *,struct dentry *,int, struct nameidata *); struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *); ... }; 

Ogni tipo registrato di filesystem registra quindi le proprie funzioni per la create , la lookup e le restanti funzioni. Il resto del codice può utilizzare le inode_operations generiche:

 struct inode_operations *i_op; i_op -> create(...); 

Il C ++ non è così lontano da C.

Le classi sono strutture con un puntatore nascosto a una tabella di puntatori di funzione chiamata VTable. Il Vtable stesso è statico. Quando i tipi puntano a Vtables con la stessa struttura ma dove i puntatori puntano ad altre implementazioni, si ottiene il polimorfismo.

Si consiglia di incapsulare la logica delle chiamate in funzione che prende la struttura come parametro per evitare l’ingombro del codice.

Dovresti anche istanziare le strutture incapsulcate e inizializzare le funzioni (questo è equivalente a un costruttore C ++) e cancellare (distruttore in C ++). Queste sono comunque buone pratiche.

 typedef struct { int (*SomeFunction)(TheClass* this, int i); void (*OtherFunction)(TheClass* this, char* c); } VTable; typedef struct { VTable* pVTable; int member; } TheClass; 

Per chiamare il metodo:

 int CallSomeFunction(TheClass* this, int i) { (this->pVTable->SomeFunction)(this, i); } 

Ho guardato le risposte di tutti gli altri e mi sono inventato questo:

 #include  typedef struct { int (*get)(void* this); void (*set)(void* this, int i); int member; } TheClass; int Get(void* this) { TheClass* This = (TheClass*)this; return This->member; } void Set(void* this, int i) { TheClass* This = (TheClass*)this; This->member = i; } void init(TheClass* this) { this->get = &Get; this->set = &Set; } int main(int argc, char **argv) { TheClass name; init(&name); (name.set)(&name, 10); printf("%d\n", (name.get)(&name)); return 0; } 

Spero che risponda ad alcune domande.

L’Appendice B dell’articolo Open Open Reusable Object Models , di Ian Piumarta e Alessandro Warth di VPRI è un’implementazione di un modello Object in GNU C, circa 140 righe di codice. È una lettura affascinante!

Ecco la versione non collegata della macro che invia messaggi agli oggetti, usando un’estensione GNU a C ( espressione di dichiarazione ):

 struct object; typedef struct object *oop; typedef oop *(*method_t)(oop receiver, ...); //... #define send(RCV, MSG, ARGS...) ({ \ oop r = (oop)(RCV); \ method_t method = _bind(r, (MSG)); \ method(r, ##ARGS); \ }) 

Nello stesso documento, vtable_delegated un’occhiata object , vtable , vtable_delegated e le strutture dei symbol , e le funzioni _bind e vtable_lookup .

Saluti!

Le funzioni del file fopen, fclose, sono esempi di codice OO in C. Invece dei dati privati ​​in class, funzionano sulla struttura FILE che viene utilizzata per incapsulare i dati e le funzioni C agiscono come funzioni di class membro. http://www.amazon.com/File-Structures-Object-Oriented-Approach-C/dp/0201874016

Da Wikipedia: nei linguaggi di programmazione e nella teoria dei tipi, il polimorfismo (dal greco πολύς, polys, “many, much” e μορφή, morphē, “form, shape”) è la fornitura di una singola interfaccia a entity framework di tipi diversi.

Quindi direi che l’unico modo per implementarlo in C è l’utilizzo di argomenti variadici insieme ad una gestione di informazioni di tipo (semi) automatico. Ad esempio in C ++ puoi scrivere (mi dispiace per banalità):

 void add( int& result, int a1, int a2 ); void add( float& result, float a1, float a2 ); void add( double& result, double a1, double a2 ); 

In C, tra le altre soluzioni, il meglio che puoi fare è qualcosa del genere:

 int int_add( int a1, int a2 ); float float_add( float a1, fload a2 ); double double_add( double a1, double a2 ); void add( int typeinfo, void* result, ... ); 

Allora hai bisogno di:

  1. implementare “typeinfo” con enum / macro
  2. per implementare l’ultima funzione con roba stdarg.h
  3. per dire addio al controllo di tipo statico C

Sono quasi sicuro che qualsiasi altra implementazione del polimorfismo dovrebbe assomigliare molto a questa. Le risposte di cui sopra, invece, sembrano cercare di indirizzare l’ereditarietà più del polimorfismo!

 #include  typedef struct { int x; int z; } base; typedef struct { base; int y; int x; } derived; void function_on_base( base * a) // here I can pass both pointers to derived and to base { printf("Class base [%d]\n",a->x); printf("Class base [%d]\n",a->z); } void function_on_derived( derived * b) // here I must pass a pointer to the derived class { printf("Class derived [%d]\n",b->y); printf("Class derived [%d]\n",b->x); } int main() { derived d; base b; printf("Teste de poliformismo\n"); bx = 2; dy = 1; bz = 3; dx = 4; function_on_base(&b); function_on_base(&d); function_on_derived(&b); function_on_derived(&d); return 0; } 

L’output era:

 Class base [3] Class base [1] Class base [4] Class derived [2] Class derived [3] Class derived [1] Class derived [4] 

quindi funziona, è un codice polimorfico.

ZioZeiv ci ha spiegato all’inizio.

Anche per build funzionalità OO in C, puoi guardare le risposte precedenti.

Ma, (come è stato chiesto in altre domande reindirizzate a questo) se vuoi capire che cos’è il polimorfismo, con esempi in linguaggio C. Forse ho torto, ma non riesco a pensare a qualcosa di così facile da capire come l’aritmetica dei puntatori C. A mio avviso, l’ aritmetica del puntatore è intrinsecamente polimorfica in C. Nell’esempio seguente la stessa funzione (metodo in OO), cioè l’addizione (+), produrrà un comportamento diverso a seconda delle proprietà delle strutture di input.

Esempio:

 double a*; char str*; a=(double*)malloc(2*sizeof(double)); str=(char*)malloc(2*sizeof(char)); a=a+2; // make the pointer a, point 2*8 bytes ahead. str=str+2; // make the pointer str, point 2*1 bytes ahead. 

Disclaimer: Sono molto nuovo in C e non vedo l’ora di essere corretto e di imparare dai commenti di altri utenti, o addirittura di cancellare completamente questa risposta, nel caso fosse sbagliato. Grazie molto,