2010-10-22 4 views
5

È possibile passare oggetto inizializzato a una classe principale come nel seguente esempioRiferimento oggetto non inizializzato iniside costruttore

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; 
}; 

In class T costruttore, c è un riferimento all'oggetto inizializzato. Se utilizzava l'oggetto durante la costruzione, questo potrebbe causare un errore. Ma dal momento che non lo è, questo compila e funziona bene. La mia domanda è: blocca qualche tipo di paradigma o di buone direttive di progettazione? Se è così, quali sono le alternative, perché ho trovato utile allocare un oggetto richiesto dal genitore in una sottoclasse.

In una nota a margine, mi chiedo il motivo per cui non è possibile modificare l'ordine di inizializzazione, in modo che il costruttore della classe base venga chiamato dopo l'inizializzazione di alcuni membri.

risposta

2

È possibile , ma ottieni un comportamento indefinito.

Nelle utility di Boost, è disponibile lo base-from-member idiom creato da R. Samuel Klatchko. Fondamentalmente, si crea una base privata al posto del membro privato. Questa base di viene inizializzata prima, ed è possibile utilizzarlo per altre basi: utility

// ... 

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), 
     { 
     }; 
}; 

di Boost elimina il codice ripetuto.

2

Ho visto molto e molti compilatori avviseranno. Va bene se il costruttore T non interroga mai il riferimento c.

Se non si desidera l'avviso, è necessario eseguire due fasi di costruzione. Fare un Init(C&) metodo protetto in T, e quindi chiamare nel corpo ST costruttore - purtroppo m_c sarà bisogno di un puntatore a farlo (dal momento che i riferimenti non possono essere riassegnati ad un altro oggetto)

2

Passare un riferimento o un puntatore a qualcosa di non inizializzato è tecnicamente perfettamente OK.

Ma la ragione che chiedi è probabilmente che pensi che qualcosa possa facilmente andare storto, che attraverso una catena di chiamate si possa inavvertitamente accedere all'oggetto prima che sia stato inizializzato. E penso che sia una preoccupazione valida. E c'è un'altra cosa che può andare storto, e cioè che il codice in classe di base T può ora eventualmente invalidare l'invariante di classe di ST modificando direttamente un membro di dati di ST esempio ...

Quindi, penso che sia un po 'rischioso.

Per quanto riguarda l'ordine di inizializzazione, C++ si basa sull'idea di costruire da parti in su, in una gerarchia. Se un costruttore lancia poi le cose completamente costruite vengono distrutte, automaticamente. Ciò sarebbe più difficile o meno efficiente con un ordine di costruzione più arbitrario.

Cheers & h.,