Una struttura C può comportarsi come se avesse una funzione?


13

Uso C e structs dove una struttura può avere membri ma non funzioni. Supponiamo per semplicità che voglio creare una struttura per le stringhe che ho nominato stre voglio essere in grado di fare str.replace(int i, char c)dov'è il'indice della stringa ed cè il carattere che sostituisce il carattere in posizione i. Questo non sarebbe mai possibile poiché le strutture non possono avere funzioni o esiste ancora un modo per implementare questo comportamento e imitare che una struttura potrebbe avere una (semplice) funzione che in realtà è solo la struttura che si copia in una nuova struttura e aggiorna il suo campi, cosa potrebbe fare?

Quindi replacepotrebbe essere un terzo membro della struttura che punta a una nuova struttura che viene aggiornata quando si accede o simile. Potrebbe essere fatto? O c'è qualcosa di incorporato o qualche teoria o paradigma che impedisce la mia intenzione?

Lo sfondo è che sto scrivendo il codice C e mi ritrovo a reinventare funzioni che so siano incorporate nelle librerie nei linguaggi OOP e che OOP sarebbe un buon modo per manipolare stringhe e comandi.


5
Sinceramente penso che sarebbe meglio scrivere funzioni gratuite per fare questo genere di cose. Tuttavia, se hai il necessario moxie, leggi cs.rit.edu/~ats/books/ooc.pdf
Robert Harvey,

5
Le strutture possono includere variabili che sono puntatori a funzioni. Nessuna eredità incorporata ma è possibile creare un'istanza della struttura con i puntatori che puntano a funzioni diverse con la stessa firma. Spesso vorrai rendere il primo parametro della funzione un puntatore alla struttura.
James McLeod,

29
sostituire (& str, i, c) è davvero molto peggio di str.replace (i, c)? La tua domanda non è in realtà sulla sostituzione delle funzioni, si tratta di provare a sfumare una nuova sintassi in C.
whatsisname

1
@RobertHarvey Grazie per il link cs.rit.edu/~ats/books/ooc.pdf . Bel libro (e il prezzo è giusto).
John Forkosh,

3
@whatsisname: In C, devi comunque passare il puntatore struttura alla funzione, quindi finisci str.replace(&str, i, c)comunque. C ++ automatizza il passaggio del thispuntatore, ovviamente.
Jonathan Leffler,

Risposte:


21

La tua funzione dovrebbe apparire così.

void
replace(struct string * s, int i, char c);

Questo accetta un puntatore all'oggetto su cui operare come primo parametro. In C ++, questo è noto come this-pointer e non deve essere dichiarato esplicitamente. (Contrastare questo con Python dove deve.)

Per chiamare la tua funzione, dovresti anche passare esplicitamente quel puntatore. Fondamentalmente, si scambia la o.f(…)sintassi per la f(&o, …)sintassi. Non un grande affare.

La storia diventa più coinvolgente se vuoi supportare il polimorfismo (aka virtualfunzioni). Può anche essere emulato in C (l'ho mostrato per questa risposta .) Ma non è carino farlo a mano.

Come ha commentato Jan Hudec , dovresti anche prendere l'abitudine di aggiungere il prefisso al nome della funzione con il nome del tipo (es. string_replace) Perché C non ha spazi di nomi, quindi può esserci una sola funzione chiamata replace.


17
Ovviamente la funzione dovrà probabilmente essere chiamata string_replace, perché C non ha nemmeno un sovraccarico di funzioni e probabilmente ne avrai un'altra replaceper qualche altro tipo ...
Jan Hudec,

2
Non può essere nominato string_replace. I nomi che iniziano con str, memo wcsseguiti da una lettera minuscola sono riservati per estensioni future.
David Conrad,

43

Le strutture possono contenere puntatori a funzioni , ma sono realmente necessarie solo per i metodi virtuali. I metodi non virtuali in C orientati agli oggetti vengono generalmente eseguiti passando la struttura come primo argomento a una funzione regolare. Guarda Gobject per un buon esempio di un framework OOP per C. Utilizza macro per gestire molta della piastra di caldaia richiesta per ereditarietà e polimorfismo.

C è stata creata 44 anni fa. È una lingua molto popolare per l'open source. Non sei la prima persona a pensare che le stringhe C standard siano ingombranti con cui lavorare. Effettua alcune ricerche per le librerie di stringhe C. Non è necessario reinventare la ruota.


2
Un altro esempio notevole è CPython. Il codice usa molti concetti di OOP eppure è puro al 100% C.
Bakuriu

@Bakuriu Penso che tu stia confondendo Cython e CPython
cat

1
@cat Probabilmente significa l'API C di Python, Cython non è puro al 100% C. docs.python.org/c-api/intro.html
JAB

5
@cat No. Guarda le fonti CPython. La maggior parte delle cose viene effettivamente eseguita utilizzando il paradigma OOP e forniscono un'API OOP che corrisponde principalmente all'API python.
Bakuriu,

1
@Bakuriu Oh, intendi il runtime di Python, la sorgente e l'API C non il linguaggio Python. il tuo commento non è stato molto chiaro
gatto

8

Con i puntatori a funzione, puoi fare:

str.replace(&str, i, c);

Questo è generalmente utile solo se l'implementazione può cambiare, nel qual caso dovresti usare una vtable in modo che l'overhead sia solo un puntatore per struttura:

str.vtable->replace(&str, i, c);

3
Tenderei ancora a chiamarlo come string_replace (& str, i, c) quindi utilizzare la vtable all'interno di string_replace piuttosto che il sito di chiamata sia a conoscenza della vtable.
Pete Kirkham,

2
@Pete I nomi che iniziano con str(o memo wcs) e una lettera minuscola sono riservati dallo standard C per le future estensioni, quindi non chiamarlo string_replace. str_replaceè ok.
David Conrad,

3

Sì, possono, in un certo senso. Puoi sfruttare il fatto che C consente ai puntatori di blocchi funzionali in memoria, noti anche come puntatori di funzioni, e che puoi creare un'interfaccia come il polimorfismo e le funzioni virtuali (anche se non è così carina).

Ho scritto un post sul blog su questo argomento, a seguito di una domanda di uno dei miei studenti, di recente, relativa al codice simile all'interfaccia in C e Go, puoi leggerlo qui:

Post di blog su interfacce non OO

Vedi se ti dà qualche idea.

Puoi anche inserire una funzione gratuita nel tuo codice e utilizzare un "questo" puntatore, il che significa che passi un puntatore a una struttura esistente su cui lavorare, come descritto in altre risposte.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.