2010-11-05 22 views
5

Eventuali duplicati:
Can you write object oriented code in C?Esperimento: C orientato agli oggetti?

Hi!

Solo per il gusto di farlo, ho sperimentato questi ultimi due giorni con la creazione di un ambiente di oggetti molto semplice, molto semplice in C. puro. Ho lavorato con macro, collegamenti dinamici, strutture di descrizione del tipo e simili, e sono arrivato al seguente:

string_o str = new(String, "hello world"); 
list_o list = new(List); 

List.pushf(list, str); 

printf("In the list: \"%s\"\n", 
     String.text(List.popf(list))); 

delete(list); 
delete(str); 

appare e funziona un pò bello, ma io non riesco a capire il modo di falsi metodi di istanza. Non riesco a superare Class.function(instance), non senza sostituzioni macro globali per nomi di funzioni, che vanifica lo scopo dell'incapsulamento.

Ancora, questo è un esperimento, solo per la sfida e il divertimento =). Ragazzi, potete aiutarmi a trovare un modo per farlo? Non voglio usare una pre-elaborazione aggiuntiva, solo macro C e GCC.

modifica> dimenticato di dire - Non voglio che ogni istanza contenga i puntatori di funzione nella sua struttura. Questo mi darebbe la sintassi del metodo, ma significherebbe che un oggetto di dati a 4 byte avrebbe una dozzina di puntatori di funzione copiati su ogni istanza. È un po 'come barare = P haha ​​

Grazie in anticipo!

+3

non è questo il motivo per cui hanno creato cpp?: P – Tobias

+3

Associare ogni 'classe' a una tabella di puntatori di funzione che vengono eseguiti quando si chiama una 'funzione membro'? – birryree

+0

@Tobias: _shudder_, spero di no! [C++: un polipo fatto inchiodando gambe extra su un cane.] (Http://en.wikiquote.org/wiki/Programming_languages#C.2FC.2B.2B) - Steve Taylor: P –

risposta

12

L'orientamento dell'oggetto in C viene normalmente eseguito con i puntatori di funzione. Ciò significa una struttura che contiene non solo i dati di un'istanza, ma anche le funzioni da chiamare.

È il modo più semplice per eseguire l'ereditarietà e il polimorfismo in C. A titolo di esempio, ecco un esempio di comunicazione orientata agli oggetti.

Ha solo un metodo open ma è possibile vedere come si differenzia per le sottoclassi TCP e HTML. Avendo una routine di inizializzazione che imposta una funzione specifica della classe, si ottiene il polimorfismo.

#include <stdio.h> 

// The top-level class. 

typedef struct _tCommClass { 
    int (*open)(struct _tCommClass *self, char *fspec); 
} tCommClass; 

// Function for the TCP class. 

static int tcpOpen (tCommClass *tcp, char *fspec) { 
    printf ("Opening TCP: %s\n", fspec); 
    return 0; 
} 
static int tcpInit (tCommClass *tcp) { 
    tcp->open = &tcpOpen; 
    return 0; 
} 

// Function for the HTML class. 

static int htmlOpen (tCommClass *html, char *fspec) { 
    printf ("Opening HTML: %s\n", fspec); 
    return 0; 
} 
static int htmlInit (tCommClass *html) { 
    html->open = &htmlOpen; 
    return 0; 
} 

// Test program. 

int main (void) { 
    int status; 
    tCommClass commTcp, commHtml; 

    // Same base class but initialized to different sub-classes. 
    tcpInit (&commTcp); 
    htmlInit (&commHtml); 

    // Called in exactly the same manner. 

    status = (commTcp.open)(&commTcp, "bigiron.box.com:5000"); 
    status = (commHtml.open)(&commHtml, "http://www.microsoft.com"); 

    return 0; 
} 

una risposta più completa può essere trovato here.

In risposta al tuo commento:

Non voglio le funzioni contenute in ogni singola istanza.

Probabilmente hai ragione. Non è necessario duplicare tali informazioni quando sarà uguale per ogni istanza di una singola classe.

C'è un modo semplice per aggirare questo. Piuttosto che avere ogni istanza con il proprio set di puntatori di funzione, si crea una struttura che li trattiene per la classe, quindi ogni istanza ottiene un puntatore a quella struttura.

Ciò consente di risparmiare un po 'di spazio al costo (minimo) di dover eseguire due livelli di riferimento indiretto per chiamare una funzione.

+0

Grazie per la risposta, ma ho dimenticato di dire che non voglio le funzioni contenute in ogni singola istanza. Immagina se ogni nodo di lista, o intero avvolto, o qualsiasi cosa, dovesse contenere 20 puntatori di funzione! – slezica

+1

Bene, allora potreste avere un puntatore _single_ nella struttura che puntava ad una matrice specifica per una classe di puntatori di funzione. Dovresti usare la doppia indirezione per chiamare le funzioni piuttosto che la singola indiretta, ma ti farebbe risparmiare spazio. Lo aggiungerò alla mia risposta. – paxdiablo

+0

Scusa, ho appena letto quello! Sì, non sono preoccupato di non essere * in grado * di raggiungere le funzioni. Potrei fare (supponiamo che un puntatore alla classe nell'oggetto si chiami 'f') object-> f-> fun (object); ma sembra brutto come l'inferno hahah. Sto provando a macinare fino a object.fun(); - Non so se è possibile del tutto però. – slezica

Problemi correlati