2009-06-07 24 views
27

Permítanme decir primero que tengo una buena cantidad de experiencia tanto en C como en C++. Sin embargo, estoy comenzando un nuevo proyecto en C y he estado trabajando en lenguajes orientados a objetos por tanto tiempo (C# y C++) que tengo problemas para encontrar una manera efectiva de encapsular la funcionalidad en un lenguaje de procedimientos. Mi primera idea fue simplemente caer de nuevo en mi conocimiento OO y estructurar algo así como:Cómo estructurar un programa C efectivamente

struct Foo 
{ 
    int x; 
    char *y; 
}; 

struct Foo *new_Foo() 
{ 
    return (struct Foo *)malloc(sizeof(struct Foo)); 
} 

void Foo_member_function(struct Foo *foo, int z) 
{ 
    foo->x = z;  
} 

Pero eso sólo parece tedioso y contrario al espíritu de C. Por no mencionar que es OO un hombre pobre.

Este programa en última instancia va a ser bastante considerable, por lo que a partir de una buena organización de diseño es fundamental. Me imagino que con los años de desarrollo en C, se han desarrollado ciertos patrones de diseño sobre cómo estructurar mejor el código para la mantenibilidad. Al igual que la programación funcional, espero que la programación de procedimientos tenga un paradigma que sea limpio y bastante legible.

También se aceptan apuntes de artículos y libros relevantes.

+0

Odio elegir solo una respuesta porque todas tienen trucos útiles, pero la referencia del puntero opaco fue probablemente la más útil de la que no tenía conocimiento. ¡Gracias! – HVS

Respuesta

15

Esta es una práctica bastante normal y sensata. Pero intente no exponer el diseño de la estructura en los archivos de encabezado, de modo que tenga cierta flexibilidad en la forma en que se implementa y administre mejor sus dependencias.

Ver Opaque pointer para más detalles.

+1

me recuerda a HWND, y win32 C nativo – bobobobo

11

Lo que está sugiriendo es la forma en que siempre escribí los programas C en los días en que hacía tal cosa. No creo que sea "poor mans OO", creo que es una práctica de programación procedimental sensata.

he de señalar un par de cosas acerca de su código C:

  • typedef struct uso con las definiciones de modo que no es necesario para esparcir la palabra clave 'struct' a través del código
  • único uso cuando arroja en realidad son necesarios: el molde en el valor de retorno de malloc() es innecesario
+0

Buenos consejos. Lo que quise decir con "poor mans OO" fue que era un OO muy limitado (es decir, sin polimorfismo, sin encapsulado, etc.). – HVS

+1

pero tenga en cuenta que typedefs se consideran malas prácticas para algunos, incluido el personal de kernel de Linux – temp2290

1

C ha sido un lenguaje de bajo nivel y, en este sentido, sería muy útil organizar sus estructuras de datos de acuerdo con su código funciones y módulos.

Le sugiero que use typedefs y enumeraciones donde desee crear objetos de datos. Use macros o funciones estáticas para inicializar, asignar y 'destruir' según sea necesario.

3

Hmmm ... Solíamos usar convenciones de nomenclatura ... Ergo: str * hace cosas con qué estructura de datos común? Entonces, ¿tal vez solo tome la sintaxis de C# y s /./_/ g?

  • foo_constructor
  • foo_destructor
  • foo_someMethod
  • foo_someMethod2 // No hay sobrecarga en ANSI C
  • foo_otherMethod

... y no hay ninguna herencia. ..

  • foo2_constructor
  • foo2_destructor
  • foo2_someMethod // y no hay ningún polimorfismo

Pero mira el lado bueno ... se puede utilizar puntero-a-puntero-a puntero-a-función-retornando-a-puntero-a-puntero-int! ¡Oh, la alegría!

Mi mejor consejo es aprender las lecciones de Java (y por inferencia C#) y estructurar tus bibliotecas para NO tener efectos secundarios ... más típicos == menos dolores de cabeza ... y si tu entrenamiento es como siga este sabio consejo por favor hágamelo saber ;-)

Saludos. Keith.

+0

Por "efectos secundarios", supongo que quiere decir que tiene variables estáticas, globales, etc. Obviamente, las bibliotecas tendrían efectos secundarios sobre los "objetos" que modifican. – HVS

+0

Generalmente, puede devolver un estado nuevo en lugar de cambiar uno existente para actualizar algún estado, esto está en línea con la programación funcional y hará que las dependencias de flujo de datos sean mucho más explícitas y más fáciles de seguir. – none

2

Esa es una forma bastante razonable de escribir un programa en C. Hay otra aplicación grande por ahí, que hace más o menos lo mismo, llamado kernel de Linux. Algunas de las características OO-casi no utilizan en:

  • estructuras y operaciones en estructuras para la encapsulación al igual que en el ejemplo
  • punteros a estructuras de base como una forma de herencia del pobre - encontrará un montón de referencias a struct kobject de allí
  • macros para generar funciona como un reemplazo para la programación de la plantilla
1

Estoy de acuerdo con las sugerencias anteriores. Lo está haciendo de la mejor manera ... si desea programar en C.

Por supuesto, puede escribir un preprocesador para generar automáticamente estas declaraciones y cosas para usted ... tal vez use una declaración de "Clase". .. ponga las funciones que quiere que sean funciones miembro dentro de la clase ... etc.

Pero lo que tenemos aquí es un compilador simple de C++ a C. ¿Por qué no simplemente programar en C++, usar un compilador real de C++, usar interfaces limpias y simplemente vincular el código C++ con el código C? ¿Cuál es la razón por la que necesita codificar en C contra C++ de todos modos? O, si lo necesita, genere el código C del compilador y compile el código C de salida junto con cualquier otra cosa que necesite.

+1

Realmente no soy fan de C++, a pesar de que ha mejorado enormemente en los últimos años (Boost es una gran biblioteca). Aparte de eso, parte de este proyecto es de un nivel bastante bajo, que es una de las razones para elegir C. El otro es que será de código abierto y desea mantenerlo lo más flexible posible. Yo * podría * hacerse en C++, pero eso causaría más problemas que creo que valen la pena. – HVS

+1

No necesita usar todas las funciones, solo adhiérase a un subconjunto muy simple, es decir, clases, métodos, constructores, destructores, mantenga el resto en el estándar c. Para las versiones de código abierto, puede ejecutar el compilador C++ a C y distribuir el código C. –

+0

C es lo que hacemos entre el nivel inferior, C++ casi no tiene ningún valor para el ecosistema de Linux. O lo haces bien, lo tomas muy lento con C, o usas un lenguaje moderno como Golang para cosas que aún quieres compilar por completo. C++ es desarrolladores sobre el código, y eso es antitético al ethos, Linus lo hizo bien. – TechZilla

0

He estado trabajando en un proyecto por un tiempo donde la biblioteca necesita estar en C, pero quiero tener alguna forma de funcionalidad OO. Estoy haciendo algo similar a esto con un poco más de detalle.

struct klass { 
    char * value; 

    void (*set_value) (struct klass *, const char *); 
    void (*destroy) (struct klass *); 
}; 

static void 
klass_method_set_value (struct klass * k, const char * value) { 
    if (k->value == NULL) { 
    } 
} 

static void 
klass_object_desetroy (struct klass * k) { 
    free (k); 
    k = NULL; 
} 

static void 
klass_method_destroy (struct klass * k) { 
    klass_object_destroy (k); 
} 

static struct klass * 
klass_object_init (void) { 
    struct klass * obj = (struct klass *) malloc (sizeof (struct klass*)); 

    /* members */ 
    obj->value = NULL; 

    /* methods */ 
    obj->set_value = klass_method_set_value; 
    obj->destroy = klass_method_destroy; 
    return obj; 
} 

struct klass * 
klass_new (void) { 
    return klass_object_init(); 
} 

Perdóname si algo está mal; lo escribió un poco rápido.

+0

Sí, eso es lo que quería evitar. Sin embargo, he escuchado que eso es básicamente lo que Stroustrup codificó como el primer compilador de C++. – HVS

Cuestiones relacionadas