Une structure C peut-elle se comporter comme si elle avait une fonction?

13

J'utilise C et structs où une structure peut avoir des membres mais pas des fonctions. Supposons par souci de simplicité que je veuille créer une structure pour les chaînes que je nomme stret que je veux pouvoir faire str.replace(int i, char c)iest l'index de la chaîne et cest le caractère pour remplacer le caractère à la position i. Cela ne serait-il jamais possible car les structures ne peuvent pas avoir de fonctions ou existe-t-il encore un moyen d'implémenter ce comportement et d'imiter qu'une structure pourrait avoir une fonction (simple) qui n'est en fait que la structure se copiant dans une nouvelle structure et mettant à jour son domaines, ce qu'il pourrait faire?

Il replacepourrait donc s'agir d'un troisième membre de la structure qui pointe vers une nouvelle structure qui est mise à jour lors de son accès ou similaire. Cela pourrait-il être fait? Ou y a-t-il quelque chose de intégré ou une théorie ou un paradigme qui empêche mon intention?

L'arrière-plan est que j'écris du code C et je me retrouve à réinventer des fonctions que je connais comme des bibliothèques intégrées dans les langages OOP et que OOP serait un bon moyen de manipuler des chaînes et des commandes.

Niklas
la source
5
Je pense honnêtement que vous feriez mieux d'écrire des fonctions gratuites pour faire ce genre de choses. Cependant, si vous avez le moxie nécessaire, lisez cs.rit.edu/~ats/books/ooc.pdf
Robert Harvey
5
Les structures peuvent inclure des variables qui pointent vers des fonctions. Pas d'héritage intégré mais vous pouvez instancier votre structure avec les pointeurs pointant vers différentes fonctions avec la même signature. Vous souhaiterez souvent faire du premier paramètre de la fonction un pointeur vers la structure.
James McLeod
29
remplacer (& str, i, c) est-il vraiment pire que str.replace (i, c)? Votre question ne concerne pas réellement le remplacement de fonctions, il s'agit d'essayer d'intégrer une nouvelle syntaxe en C.
whatsisname
1
@RobertHarvey Merci pour le lien cs.rit.edu/~ats/books/ooc.pdf . Beau livre (et le prix est correct).
John Forkosh
3
@whatsisname: En C, vous devez quand même passer le pointeur de structure à la fonction, donc vous vous retrouvez avec str.replace(&str, i, c)quand même. C ++ automatise thisbien sûr le passage du pointeur.
Jonathan Leffler

Réponses:

21

Votre fonction devrait ressembler à ceci.

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

Cela accepte un pointeur sur l'objet sur lequel opérer comme premier paramètre. En C ++, il s'agit du thispointeur et n'a pas besoin d'être déclaré explicitement. (Comparez cela à Python où il le faut.)

Pour appeler votre fonction, vous devez également passer ce pointeur explicitement. Fondamentalement, vous échangez la o.f(…)syntaxe pour la f(&o, …)syntaxe. Pas grave.

L'histoire devient plus impliquée si vous souhaitez prendre en charge le polymorphisme (aka virtualfonctions). Il peut également être émulé en C (je l'ai montré pour cette réponse ) mais ce n'est pas joli à faire à la main.

Comme l' a commenté Jan Hudec , vous devez également prendre l'habitude de préfixer le nom de la fonction avec le nom du type (c'est-à-dire string_replace) parce que C n'a pas d'espace de nom, il ne peut donc y avoir qu'une seule fonction nommée replace.

5gon12eder
la source
17
Bien sûr, la fonction devra probablement être appelée string_replace, car C n'a pas de surcharge de fonction non plus et vous en aurez probablement une autre replacepour un autre type…
Jan Hudec
2
Il ne peut pas être nommé string_replace. Les noms commençant par str, memou wcssuivis d'une lettre minuscule sont réservés pour de futures extensions.
David Conrad
43

Les structures peuvent contenir des pointeurs de fonction , mais ceux-ci ne sont vraiment nécessaires que pour les méthodes virtuelles. Les méthodes non virtuelles en C orienté objet sont généralement effectuées en passant la structure comme premier argument à une fonction régulière. Regardez Gobject pour un bon exemple d'un cadre OOP pour C. Il utilise des macros pour gérer une grande partie du passe-partout requis pour l'héritage et le polymorphisme.

C a été créé il y a 44 ans. C'est un langage très populaire pour l'open source. Vous n'êtes pas la première personne à penser que les cordes C standard sont difficiles à utiliser. Faites quelques recherches pour les bibliothèques de chaînes C. Vous n'avez pas à réinventer la roue.

Karl Bielefeldt
la source
2
Un autre exemple notable est CPython. Le code utilise beaucoup de concepts OOP mais il est 100% pur C.
Bakuriu
@Bakuriu Je pense que vous confondez Cython et CPython
chat
1
@cat Il signifie probablement l'API Python C, Cython n'est pas 100% pur C. docs.python.org/c-api/intro.html
JAB
5
@cat Non. Regardez les sources CPython. La plupart des choses se font en effet en utilisant le paradigme OOP, et elles fournissent une API OOP qui correspond principalement à l'API python.
Bakuriu
1
@Bakuriu Oh, vous voulez dire le runtime, la source et l'API C de Python et non le langage Python. votre commentaire n'a pas été très clair
chat
8

Avec les pointeurs de fonction, vous pouvez faire:

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

Ceci n'est généralement utile que si l'implémentation peut changer, auquel cas vous devez utiliser une table virtuelle afin que la surcharge ne soit qu'un pointeur par structure:

str.vtable->replace(&str, i, c);
o11c
la source
3
J'aurais tendance à toujours l'appeler comme string_replace (& str, i, c) puis à utiliser la table virtuelle à l'intérieur de string_replace plutôt que de faire connaître le site d'appel à la table virtuelle.
Pete Kirkham
2
@Pete Les noms commençant par str(ou memou wcs) et une lettre minuscule sont réservés par la norme C pour de futures extensions, donc ne l'appelez pas string_replace. str_replacec'est bien.
David Conrad
3

Oui, ils le peuvent, en quelque sorte. Vous pouvez utiliser le fait que C permet aux pointeurs de fonctionner en blocs de mémoire, alias pointeurs de fonction et en utilisant cela, vous pouvez créer une interface comme le polymorphisme ainsi que des fonctions virtuelles (même si ce n'est pas si joli).

J'ai écrit un article de blog sur ce sujet, suite à une question d'un de mes étudiants, récemment, relative au code d'interface en C et Go, vous pouvez le lire ici:

Article de blog sur les interfaces non OO

Voyez si cela vous donne des idées.

Vous pouvez également simplement mettre une fonction gratuite dans votre code et utiliser un pointeur "this", ce qui signifie que vous passez un pointeur sur une structure existante pour travailler, comme décrit dans d'autres réponses.

Richard Tyregrim
la source