2010-10-22 23 views
5

Es posible pasar objeto no inicializado a una clase padre como en el ejemplo siguientereferencia al objeto no inicializado iniside constructor

class C 
{ 
    public: 
     C(int i): 
      m_i(i) 
     {}; 

     int m_i; 
} 

class T 
{ 
    public: 
     T(C & c): 
      m_c(c) 
     { 
     }; 

     C & m_c; 
}; 


class ST : public T 
{ 
    public: 
     ST(): 
      T(m_ci), 
      m_ci(999) 
     { 
     }; 

     C m_ci; 
}; 

En class T constructor, c es una referencia a objeto no inicializado. Si class T usaba el objeto c durante la construcción, esto posiblemente generaría un error. Pero como no es así, esto compila y funciona bien. Mi pregunta es: ¿frena algún tipo de paradigma o buenas directivas de diseño? Si es así, ¿cuáles son las alternativas, porque me pareció útil asignar un objeto requerido por el padre en una subclase?

En una nota lateral, me pregunto por qué no es posible cambiar el orden de inicialización, por lo que se llamaría al constructor de la clase base después de la inicialización de algunos miembros.

Respuesta

2

Usted puede , pero obtienes un comportamiento indefinido.

En los servicios de Boost, encontrará el base-from-member idiom creado por R. Samuel Klatchko. Básicamente, haces una base privada en el lugar del miembro privado. Esta base se inicializa en primer lugar, y se puede utilizar para otras bases: utilidad

// ... 

class C_base 
{ 
public: 
    C_base(int i) : 
    m_ci(i) 
    {} 

    C m_ci; 
}; 


class ST : 
    private C_base 
    public T 
{ 
    public: 
     ST() : 
      C_base(999), 
      T(m_ci), 
     { 
     }; 
}; 

de Boost elimina código repetido.

2

He visto esto mucho, y muchos compiladores advertirán. Está bien si el constructor T nunca desreferencia la referencia c.

Si no desea la advertencia, debe hacer una construcción de dos etapas. Hacer una Init(C&) método protegido en T, y luego llamarlo en el cuerpo ST constructor - por desgracia m_c tendrá que ser un puntero a hacer eso (ya que las referencias no pueden ser reasignados a otro objeto)

2

Pasar una referencia o puntero a algo no inicializado es técnicamente perfectamente correcto.

Pero la razón por la que pregunta es, probablemente, que usted piensa que algo puede ir mal, que a través de una cadena de llamadas se puede acceder inadvertidamente al objeto antes de que se haya inicializado. Y creo que esa es una preocupación válida. Y hay otra cosa que pueda ir mal, a saber, que el código en la clase base T ahora puede posiblemente invalidar el invariante de clase de ST cambiando directamente a un miembro de datos de ST ejemplo ...

Por lo tanto, creo que es un poco arriesgado.

En cuanto al orden de inicialización, C++ se basa en la idea de construir desde partes arriba, en una jerarquía. Si un constructor tira, las cosas completamente construidas se destruyen automáticamente. Esto sería más difícil o menos eficiente con un orden de construcción más arbitrario.

Aclamaciones & hth.,

Cuestiones relacionadas