¿Puede una estructura C comportarse como si tuviera una función?

13

Yo uso C y structs donde una estructura puede tener miembros pero no funciones. Supongamos por simplicidad que quiero crear una estructura para las cadenas que nombre stry quiero poder hacer str.replace(int i, char c)dónde iestá el índice de la cadena y ces el carácter para reemplazar el carácter en la posición i. ¿Esto nunca sería posible ya que las estructuras no pueden tener funciones o todavía hay alguna forma en que podemos implementar este comportamiento e imitar que una estructura podría tener una función (simple) que en realidad solo es la estructura que se copia a una nueva estructura y actualiza su campos, que podría hacer?

Entonces, replacepodría ser un tercer miembro de la estructura que apunta a una nueva estructura que se actualiza cuando se accede a ella o similar. ¿Se podría hacer? ¿O hay algo incorporado o alguna teoría o paradigma que impide mi intención?

El trasfondo es que estoy escribiendo código C y me encuentro reinventando funciones que sé que son bibliotecas integradas en lenguajes OOP y que OOP sería una buena manera de manipular cadenas y comandos.

Niklas
fuente
55
Sinceramente, creo que sería mejor escribir funciones gratuitas para hacer este tipo de cosas. Sin embargo, si tiene la moxie necesaria, lea cs.rit.edu/~ats/books/ooc.pdf
Robert Harvey
55
Las estructuras pueden incluir variables que son punteros a funciones. No hay herencia incorporada, pero puede crear una instancia de su estructura con los punteros que apuntan a diferentes funciones con la misma firma. A menudo querrá hacer que el primer parámetro de la función sea un puntero a la estructura.
James McLeod
29
¿reemplazar (& str, i, c) es realmente mucho peor que str.replace (i, c)? Su pregunta no se trata realmente de reemplazar funciones, se trata de intentar introducir una nueva sintaxis en C.
llama
1
@RobertHarvey Gracias por el enlace cs.rit.edu/~ats/books/ooc.pdf . Bonito libro (y el precio es correcto).
John Forkosh
3
@whatsisname: en C, debe pasar el puntero de estructura a la función de todos modos, por lo que termina con de str.replace(&str, i, c)todos modos. C ++ automatiza el paso del thispuntero, por supuesto.
Jonathan Leffler

Respuestas:

21

Su función debería verse así.

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

Esto acepta un puntero al objeto para operar como primer parámetro. En C ++, esto se conoce como el thispuntero y no necesita declararse explícitamente. (Compare esto con Python donde tiene que hacerlo).

Para llamar a su función, también debe pasar ese puntero explícitamente. Básicamente, intercambias la o.f(…)sintaxis por la f(&o, …)sintaxis. No es un gran trato.

La historia se vuelve más complicada si quieres apoyar el polimorfismo (también conocido como virtualfunciones). También se puede emular en C (lo he mostrado para esta respuesta ), pero no es bonito hacerlo a mano.

Como ha comentado Jan Hudec , también debe acostumbrarse a prefijar el nombre de la función con el nombre del tipo (es decir string_replace) porque C no tiene espacios de nombres, por lo que solo puede haber una sola función nombrada replace.

5gon12eder
fuente
17
Por supuesto, es probable que deba llamarse a la función string_replace, porque C tampoco tiene una sobrecarga de funciones y es probable que tenga otra replacepara otro tipo ...
Jan Hudec
2
No se puede nombrar string_replace. Los nombres que comienzan con str, memo wcsseguidos de una letra minúscula están reservados para futuras extensiones.
David Conrad
43

Las estructuras pueden mantener la función punteros de , pero en realidad solo se necesitan para métodos virtuales. Los métodos no virtuales en C orientado a objetos generalmente se realizan pasando la estructura como primer argumento a una función regular. Mire Gobject para un buen ejemplo de un marco de OOP para C. Utiliza macros para manejar una gran cantidad de repeticiones necesarias para la herencia y el polimorfismo.

C fue creado hace 44 años. Es un lenguaje muy popular para el código abierto. No eres la primera persona en pensar que las cadenas C estándar son torpes para trabajar. Realice algunas búsquedas de bibliotecas de cadenas C. No tienes que reinventar la rueda.

Karl Bielefeldt
fuente
2
Otro ejemplo notable es CPython. El código usa muchos conceptos de OOP pero es 100% puro C.
Bakuriu
@Bakuriu Creo que estás confundiendo a Cython y CPython
gato
1
@cat Probablemente se refiere a la API Python C, Cython no es 100% puro C. docs.python.org/c-api/intro.html
JAB
55
@cat No. Mira las fuentes de CPython. La mayoría de las cosas se hacen utilizando el paradigma OOP, y proporcionan una API OOP que coincide principalmente con la API de Python.
Bakuriu
1
@Bakuriu Oh, te refieres al tiempo de ejecución, fuente y API C de Python, no al lenguaje Python. su comentario no lo dejó muy claro
gato
8

Con punteros de función, puede hacer:

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

Esto generalmente solo es útil si la implementación puede cambiar, en cuyo caso debe usar una tabla v para que la sobrecarga sea solo un puntero por estructura:

str.vtable->replace(&str, i, c);
o11c
fuente
3
Todavía tiendo a llamarlo como string_replace (& str, i, c) y luego usar el vtable dentro de string_replace en lugar de que el sitio de la llamada conozca el vtable.
Pete Kirkham
2
@Pete nombres que comienzan con str(o memo wcs) y una letra minúscula están reservados por el estándar de C para futuras ampliaciones, así que no lo llaman string_replace. str_replaceestá bien.
David Conrad
3

Sí, pueden, más o menos. Puede hacer uso del hecho de que C permite que los punteros funcionen en bloques en la memoria, también conocidos como punteros de función, y usando eso puede crear una interfaz como polimorfismo y funciones virtuales (incluso si no es tan bonito).

Escribí una publicación de blog sobre este tema, siguiendo una pregunta de uno de mis estudiantes, recientemente, relativa al código similar a la interfaz en C and Go, puede leerlo aquí:

Publicación de blog en interfaces que no son OO

A ver si te da alguna idea.

También podría simplemente poner una función libre en su código y usar un puntero "this", lo que significa que pasa un puntero a una estructura existente para trabajar, como se describe en otras respuestas.

Richard Tyregrim
fuente