2010-11-12 9 views
25

Mi presentimiento es que no lo es. Estoy en la siguiente situación:¿Está bien llamar a una función en la lista de inicializadores del constructor?

class PluginLoader 
{ 
    public: 
     Builder* const p_Builder; 
     Logger* const p_Logger; 

     //Others 
}; 

PluginLoader::PluginLoader(Builder* const pBuilder) 
    :p_Builder(pBuilder), p_Logger(pBuilder->GetLogger()) 
{ 
    //Stuff 
} 

O debería cambiar el constructor y aprobar un Logger* const desde donde PluginLoader se construye?

Respuesta

27

Eso está perfectamente bien y es normal. p_Builder se inicializó antes.

+0

Gee. Debo ser una puerta 'no'. :) – nakiya

+11

Es aún más así, ya que él está llamando 'pBuilder-> GetLogger()', no 'p_Builder-> GetLogger()'. Ambos son legales, pero el segundo es sensible a la variable de instancia que se reordena en la definición de la clase. – Eclipse

+0

@Eclipse: Oh, ni siquiera vi eso. @nakiya: ¿Quisiste usar el miembro o parámetro? O es seguro, como es. – GManNickG

0

Perfectamente buenas prácticas.

Yo sugeriría esto (pero su en un nivel puramente personal):

en lugar de tener las funciones llamadas en su constructor, para agruparlos en una función init, sólo con fines de flexibilidad: si más adelante tiene que crear otros constructores

+3

Si lo que estás sugiriendo es una función * privada * 'init' a la que llamas desde el constructor, no me importa, pero creo que está bien. Si lo que está sugiriendo es una función * public * 'init' que los usuarios de la clase deben invocar, es propenso a errores e incoherencias (después de crear un objeto, estaría en un estado no válido y el usuario puede olvidarlo). para llamar al 'init' o intentar usar el objeto entre la construcción y la inicialización ...) –

+0

puede usar un miembro ficticio, y hacer que el método init devuelva un tipo.Por ejemplo 'clase IDGenerator { public: IDGenerator(); bool reset(); std :: uint32_t generate(); privado: bool mReset; T_ID_set mIds; std :: uint32_t mId; }; IDGenerator :: IDGenerator() : mReset (reset()) { } bool IDGenerator :: reset() { mIds.clear(); mId = 0; return true; } ' – dgsomerton

19

Lo que tienes está bien. Sin embargo, sólo quiero advertirle que tenga cuidado no hacer esto: (GMan aludió a esto, sólo quería dejar perfectamente claro)

class PluginLoader 
{ 
    public: 
     Logger* const p_Logger; // p_Logger is listed first before p_Builder 
     Builder* const p_Builder; 

     //Others 
}; 

PluginLoader::PluginLoader(Builder* const pBuilder) 
    :p_Builder(pBuilder), 
    p_Logger(p_Builder->GetLogger()) // Though listed 2nd, it is called first. 
             // This wouldn't be a problem if pBuilder 
             // was used instead of p_Builder 
{ 
    //Stuff 
} 

Nota que hice 2 cambios en el código. Primero, en la definición de clase, declare p_Logger antes de p_Builder. En segundo lugar, utilicé el miembro p_Builder para inicializar p_Logger, en lugar del parámetro.

Cualquiera de estos cambios estaría bien, pero juntos introducen un error, porque p_Logger se inicializa primero, y se usa el p_Builder no inicializado para inicializarlo.

Recuerde siempre que los miembros se inicializan en el orden en que aparecen en la definición de la clase. Y el orden en que los pones en tu lista de inicialización es irrelevante.

Cuestiones relacionadas