Estoy tratando de crear una función dentro de una estructura, hasta ahora tengo este código:
typedef struct client_t client_t, *pno;
struct client_t
{
pid_t pid;
char password[TAM_MAX]; // -> 50 chars
pno next;
pno AddClient()
{
/* code */
}
};
int main()
{
client_t client;
//code ..
client.AddClient();
}
Error : client.h: 24: 2: error: esperado ':', ',', ';', '}' o ' atributo ' antes del token '{'.
¿Cuál es la forma correcta de hacerlo?
Respuestas:
No se puede hacer directamente, pero puede emular lo mismo usando punteros de función y pasando explícitamente el parámetro "this":
typedef struct client_t client_t, *pno; struct client_t { pid_t pid; char password[TAM_MAX]; // -> 50 chars pno next; pno (*AddClient)(client_t *); }; pno client_t_AddClient(client_t *self) { /* code */ } int main() { client_t client; client.AddClient = client_t_AddClient; // probably really done in some init fn //code .. client.AddClient(&client); }
Sin embargo, resulta que hacer esto no te compra mucho. Como tal, no verá muchas API de C implementadas en este estilo, ya que también puede llamar a su función externa y pasar la instancia.
fuente
Como han señalado otros, la incrustación de punteros de función directamente dentro de su estructura generalmente se reserva para propósitos especiales, como una función de devolución de llamada.
Lo que probablemente desee es algo más parecido a una tabla de métodos virtuales.
typedef struct client_ops_t client_ops_t; typedef struct client_t client_t, *pno; struct client_t { /* ... */ client_ops_t *ops; }; struct client_ops_t { pno (*AddClient)(client_t *); pno (*RemoveClient)(client_t *); }; pno AddClient (client_t *client) { return client->ops->AddClient(client); } pno RemoveClient (client_t *client) { return client->ops->RemoveClient(client); }
Ahora, agregar más operaciones no cambia el tamaño de la
client_t
estructura. Ahora, este tipo de flexibilidad solo es útil si necesita definir muchos tipos de clientes o si desea permitir que los usuarios de suclient_t
interfaz puedan aumentar el comportamiento de las operaciones.Este tipo de estructura aparece en código real. La capa OpenSSL BIO tiene un aspecto similar a esto, y también las interfaces del controlador de dispositivo UNIX tienen una capa como esta.
fuente
Esto solo funcionará en C ++. Las funciones en estructuras no son una característica de C.
Lo mismo ocurre con su cliente. AddClient (); llamada ... esta es una llamada para una función miembro, que es programación orientada a objetos, es decir, C ++.
Convierta su fuente a un archivo .cpp y asegúrese de compilar en consecuencia.
Si necesita ceñirse a C, el siguiente código es (más o menos) el equivalente:
typedef struct client_t client_t, *pno; struct client_t { pid_t pid; char password[TAM_MAX]; // -> 50 chars pno next; }; pno AddClient(pno *pclient) { /* code */ } int main() { client_t client; //code .. AddClient(client); }
fuente
¿Qué tal esto?
#include <stdio.h> typedef struct hello { int (*someFunction)(); } hello; int foo() { return 0; } hello Hello() { struct hello aHello; aHello.someFunction = &foo; return aHello; } int main() { struct hello aHello = Hello(); printf("Print hello: %d\n", aHello.someFunction()); return 0; }
fuente
Está intentando agrupar el código de acuerdo con la estructura. La agrupación C es por archivo. Pones todas las funciones y variables internas en un encabezado o un encabezado y un archivo de objeto ".o" compilado a partir de un archivo fuente de CA.
No es necesario reinventar la orientación a objetos desde cero para un programa en C, que no es un lenguaje orientado a objetos.
He visto esto antes. Es algo extraño. Los codificadores, algunos de ellos, tienen aversión a pasar un objeto que quieren cambiar a una función para cambiarlo, aunque esa es la forma estándar de hacerlo.
Culpo a C ++, porque ocultó el hecho de que el objeto de clase es siempre el primer parámetro en una función miembro, pero está oculto. Así que parece que no está pasando el objeto a la función, aunque sí.
Client.addClient(Client& c); // addClient first parameter is actually // "this", a pointer to the Client object.
C es flexible y puede tomar las cosas pasajeras por referencia.
La función AC a menudo devuelve solo un byte de estado o int y eso a menudo se ignora. En su caso, una forma adecuada podría ser
err = addClient( container_t cnt, client_t c); if ( err != 0 ) { fprintf(stderr, "could not add client (%d) \n", err );
addClient estaría en Client.ho Client.c
fuente
do(object, subject)
) como a las OO (subject.do(object)
), no significa que debamos dejar de probarlo. Creo totalmente que es válido señalar que esta no es la forma histórica en que se ha escrito C, y que C no necesita escribirse de esta manera (lo mismo ocurre con muchos lenguajes, especialmente los de paradigmas procedimentales, funcionales o lógicos), pero no necesito desalentar activamente el patrón. También viene con algunos beneficios