2009-10-05 7 views
5

estoy revisando algo de código y estoy viendo un montón de esto:a init o para construir

class Foo 
{ 
public: 
    Foo() 
    { 
    // 'nuffin 
    } 

    void init() 
    { 
    // actual construction code 
    } 
} ; 

La única ventaja que puedo ver es si se crea un Foo sin usar un puntero y desea para mantener su código de construcción hasta más tarde, entonces puedes.

¿Es esta una buena idea o una mala idea?

+2

Estoy un poco confundido de que coloque su pregunta como independiente del idioma (y no proporcione el idioma de destino), mientras que la pregunta se trata de revisar el código. Pensé que revisar el código estaría altamente vinculado al idioma que se estaba revisando. Si no, ¿por qué no usamos todo el mismo idioma? ;-) – KLE

+0

He editado tu pregunta para que el código tenga una coloración de sintaxis. En lugar de usar PRE, coloque 8 espacios delante de cada línea. – KLE

+1

@KLE - ahora hay un montón de espacios antes de cada línea de código. Solo deberías necesitar 4 espacios para obtener el color de la sintaxis. Hay algo divertido pasando aquí. –

Respuesta

3

En general, acepto que es algo que debe evitarse. Pero algo que ninguna de las respuestas ha abordado hasta ahora es la posibilidad de que la inicialización pueda fallar. Los constructores no pueden fallar, por lo que si su constructor asigna memoria, abre un archivo o hace cualquier otra cosa que pueda fallar, necesita una forma de decirle a la persona que llama que ocurrió un error. Si realiza la inicialización en el constructor, debe tener un indicador que indique si la inicialización tuvo éxito o no, y luego asegúrese de que la persona que llama verifique ese indicador.

Si usted tiene una rutina de inicialización separada() que debe ser llamado antes de nada más funciona, las personas que llaman son más propensos a comprobar que código de retorno que llamar a un método didInitializationSucceed() después de crear el objeto.

+2

En C++, un constructor lanzará una excepción (el caso normal) o devolverá un 0 (si está construido con (nothrow)). No dejará un objeto parcialmente construido. –

4

No me gusta. Me parece que después de la construcción, un objeto debe ser ... bueno ... construido. Ese código lo deja en un estado inválido en su lugar, que es casi nunca es algo bueno.

 

palabra comadreja inserta para dar cuenta de las circunstancias imprevistas.

0

En general, el código fuente debe ser lo más simple posible, y su ejemplo se presenta sin el contexto, por lo que es más complicado de lo necesario y por lo tanto su ejemplo es una mala idea.

Sin embargo, puede haber algunos contextos semánticos, donde puede tener sentido poder entregar objetos no inicializados; por ejemplo, si el contexto requiere un contenedor para tener objetos pero no desea inicializarlos hasta más tarde porque la inicialización es lenta y/o tal vez los objetos no son necesarios. En esos casos, la complejidad adicional puede hacer que otra cosa sea más simple.

1

Creo que el constructor debería básicamente hacer la parte init() también. A menos que el objeto esté completamente construido, no debe usarse.

Además, la inicialización en el constructor le permite hacer uso de RAII. El punto básico de RAII es representar un recurso por un objeto local, inicializar en el constructor, de modo que el destructor del objeto local libere el recurso. De esta forma, el programador no puede olvidarse de liberar el recurso.

2

La construcción en dos etapas generalmente se considera una mala idea, si hay métodos en la clase que se basan en que el objeto está en un estado inicializado. En general, prefiero los constructores que garantizan que el objeto está en buen estado, o si eso no se puede hacer (quizás porque algunos de los argumentos al constructor no son válidos), lanza una excepción, por lo que nunca hay una instancia de tu clase que sea en mal estado.

Exigir que los consumidores de su objeto recuerden llamar al init() es una mala idea, porque no es así.

1

Un caso donde esto puede aplicarse es cuando 'Foo' es un atributo de otra clase y no se puede construir completamente antes de que se complete la clase padre. Sólo entonces puede 'Foo' ser 'rellenado'.

0

La diferencia es que la inicialización ocurre después de la llamada al constructor de la superclase, pero antes de que se ejecute cualquier código en el constructor de clase local. Por lo tanto, realmente depende de tus necesidades.

+0

¿En qué idioma sucedería eso? Si construye un objeto utilizando este método, se ejecuta cualquier constructor de superclase, se ejecuta el constructor de clase y luego se invoca a init(). –

0

Aunque no se puede considerar una forma normal o preferida de construir objetos, en algunas circunstancias tal vez sea un camino por recorrer. Por ejemplo, puede necesitar construir un objeto solo para indicar su existencia (en alguna lista, donde el conteo sí importa, etc.), pero para iniciarlo más tarde solo si este objeto en particular se usa por primera vez ya que la inicialización de toda la colección de objetos tomar mucho tiempo.

En ese caso, es bueno exponer el hecho de que el objeto no puede inicializarse incluyendo un método como isInitialized(). También de esa manera puede transferir la inicialización a otro hilo para no bloquear el hilo principal de la aplicación.

1

En algunos idiomas (léase: C++) no puede llamar a un constructor desde otro constructor, por lo que si desea una parte común de varios constructores, debe ponerlo en un método separado, y he visto el nombre init() utilizado para eso. Pero eso no es de lo que estás hablando?

+0

+1: Incluso en los idiomas en los que puede llamar a otro constructor (léase: Java), puede haber algunas restricciones (como tener que llamarlo como una primera cosa en el otro cuerpo del constructor), que es posible que desee solucionar. Sin embargo, en ese caso, implementaría el método init() como privado. – quosoo

1

Utilizo contructor e init si estoy instanciando objetos basados ​​en una llamada a la base de datos. Entonces, si necesito un objeto vacío para poder poblarlo y luego guardarlo en la base de datos, lo construyo sin parámetros y no llamo a init(). Mientras que si necesito recuperar los miembros del objeto de la base de datos, voy a contruct($param) y paso el $ param a init($param).

Cuestiones relacionadas