2009-03-23 8 views
19

Cuando me presentan problemas de programación, naturalmente comienzo a dividirlos en objetos lógicos en mi cabeza. Quién tiene qué responsabilidad, a quién pertenece qué, quién se deriva de qué, etc.¿Luchando con C procedente de tierra orientada a objetos?

Estoy luchando con C. Simplemente no entiendo cómo hacer las cosas en un Lenguaje de procedimiento.

¿Puede un programador en C con experiencia ayudarme a explicar cómo debo pensar sobre mis programas durante el tiempo de diseño?

Por ejemplo, quiero escribir mi propia clase de semáforo. Naturalmente, necesitaría una estructura de datos Queue para mi programa, que también me gustaría escribir. Si tuviera que hacer esto en Java o C#, podría simplemente crear rápidamente una clase Queue y crear una nueva instancia en mi clase de Semaphore.

Pero en C, no hay objetos. Entonces, ¿tengo que alinear todo el comportamiento de mi estructura de datos de Queue?

¿Alguien me puede ayudar a "conseguirlo"?

relacionadas: what is the best way to plan and organize development of an application in c

Respuesta

30

Pero en C, no hay objetos. Entonces, ¿ tengo que alinear todo el comportamiento de mi estructura de datos de cola?

hacer esto.

  1. Defina su clase sin embargo se siente cómodo haciendo el diseño de OO.

  2. Escriba los atributos de su clase como una estructura C-language.

  3. Pon esa estructura en un archivo de cabecera, junto con todas las funciones que operan en esa estructura. Asegúrese de que MyStruct * self es el primer argumento para todas estas "funciones de método".

  4. Escriba un módulo C con todos los cuerpos de las funciones del método.

Poor-person's OO in C. Funciona bien. Simplemente sea disciplinado acerca de poner todo en la estructura que necesita, variables de instancia públicas y privadas, todo.

En general, evite tratar de tener variables privadas en primer lugar.No tiene toda la potencia de un compilador OO, por lo que no se moleste con las características de bajo valor como "privado" o "protegido".

+0

Los caracteres de subrayado principales son reservados y no se deben utilizar. –

+1

Dependiendo de cómo esté definida su API, también puede usar variaciones en PIMPL para definir variables privadas, o conversión a/desde "char reserved [SOME_SIZE]" para que el usuario no pueda ver cuáles son las variables privadas. –

+1

@evan nombres con guiones bajos principales solo se reservan en alcance global, no para miembros de estructura –

15

todavía se puede pensar orientado con C. objeto

Sólo tiene que crear una estructura y un conjunto de funciones que toman un puntero a una instancia de esa estructura como su primer parámetro.

En cuanto al polimorfismo, puedes pasar el tamaño de la estructura como el primer miembro de la estructura, para que sepas cómo lanzarlo.

Hay una gran pdf of object oriented programming with ANSI-C here.

17

Me gustaría modificar la respuesta de S. Lott utilizar un opaque pointer para realizar ocultación de datos de los miembros de la estructura:

  1. definir la clase sin embargo que desee mediante el diseño normal de OO.
  2. Las variables miembro de su clase entran en una estructura de lenguaje C.
  3. En el archivo de encabezado, no desea exponer las variables miembro de su objeto (ya que éstas serían "privadas" en un idioma OO). En su lugar, utilice un puntero opaco, es decir,
    typedef struct mystruct_s *mystruct_t; // first argument to all your methods
  4. Para todos los métodos que desea que sean "públicos", coloque sus firmas en su archivo .h. Los cuerpos de los métodos deben ir al archivo .c, y los métodos "privados" solo deben definirse en el archivo .c y también deben declararse estáticos para que sus símbolos no colisionen con los símbolos definidos en otros archivos.

Convenciones de nomenclatura inteligentes como guiones bajos no son necesarios con este método, pero significa que todas las variables de miembro serán privadas. Las funciones pueden ser públicas o privadas, aunque las funciones públicas son parte de un espacio de nombres global, por lo que puede calificar sus nombres con un nombre de "paquete" como mystruct_push(), mystruct_pop(), etc.

También debe dejar en claro si la persona que llama o la biblioteca es responsable de llamar al malloc() y free(). Lo más probable es que tenga los métodos mystruct_t *create() y void destroy(mystruct_t *target).

+0

Estoy de acuerdo; He votado la respuesta de S. Lott, pero he cambiado mi voto a esto porque ocultar el contenido de la estructura es la mejor manera de hacerlo: he hecho exactamente esto muchas veces y funciona * realmente * bien. –

0

En segundo lugar las sugerencias para hacer "Poo hombre OO en C." También creo que podría beneficiarse de tomarse un tiempo para ver cómo funciona el OO de Perl. Básicamente, OO se logra en Perl haciendo que el intérprete suministre todos los métodos con la instancia como primer parámetro implícito. Querrá hacer lo mismo en C, explícitamente, y usar una organización realmente buena, ya que el compilador no aplicará una buena encapsulación para usted.

Por cierto, puede hacer que los miembros de sus estructuras sean privados utilizando opaque pointers. Me parece recordar que los estándares y recomendaciones de programación de GNU incluían una técnica para hacer esto básicamente fundiendo todo en void * cuando se pasaba, luego usando typedefs para nombrar cada tipo específico de puntero opaco que se suponía que se pasaría. (es decir, cada "clase")

2

Consulte el Lua C api. Ha sido mi luz de guía en lo que respecta al diseño de la interfaz C. Cada función toma un estado de Lua como un argumento principal que se convierte en su "esto". La herencia es un poco más complicada, pero Chipmunk se las arregla para hacer un buen trabajo exponiendo las funciones que toman una forma genérica y resuelve los detalles de qué función se llama realmente a través de un "klass". A menudo puede explotar void * para que las funciones tomen diferentes tipos (estructuras) de la misma manera que sobrecargaría en OO. Puede sentirse un poco hackoso a veces pero funciona bien.

4

Me costó mucho pasar de la práctica a la de OO, así que siento tu dolor.

Descubrí que, para aprender a crear objetos, era mejor pensar cómo se verían con la persona que llama. El mismo enfoque podría ayudarte, yendo por el otro camino. Considere cómo se vería la API de su componente. Una buena forma es estudiar las API C existentes (utilicé las API Java estándar como un conjunto de ejemplos de una API OO).

Estás acostumbrado a utilizar un componente de cola de algo como esto:

import some.package.Queue; 

Queue q = new Queue(); 
q.add(item); 

En una típica API C, era de esperar algo más parecido a:

#include <queue.h> // provides queue, make_queue(), queue_add(), others 

queue q = make_queue(); // queue is probably a struct, or a struct* 
queue_add(q,item); 

Cada vez que usted se encuentra pensando en objetos, haz una transformación similar.

Puede usar punteros para funciones y similares, para hacer estructuras parecidas a objetos en C, pero muchos miles de programadores en C lo han logrado sin ellas.

¡Buena suerte!

1

Originalmente C++ era sólo un compilador que escribió el código C de las fuentes de C++; luego fueron compilados por el compilador nativo de C, vinculado, etc.

Por lo tanto, todos los métodos OOP están disponibles en C, es solo que el compilador no lo ayudará y no proporciona todas las capacidades de tiempo de compilación como plantillas, anulaciones de operadores, ocultación de datos, etc.

  1. El C++ "struct" era (probablemente todavía lo es) equivalente a una "clase" con todos los miembros "públicos".
  2. Las funciones de miembro pueden implementarse como punteros de función en una estructura; esto puede proporcionar encapsulación y polimorfismo. Existen constructores en el ámbito global a menos que esté utilizando fábricas. Destructors pueden ser funciones miembro.
  3. Uso de funciones miembro de acceso, como getColor(), setColor() pueden aliviar diferencias internas y proporcionar alguna ocultación de datos. Si realmente quieres, podrías usar la sugerencia de Brian Bondy de esconderte con macros.
  4. En realidad, hay una gran cantidad de bibliotecas de software libre que proporcionan contenedores estándar - tablas hash, matrices dinámicas, listas enlazadas, etc.
Cuestiones relacionadas