C ++ - Costruttore o metodo di inizializzazione all'avvio [duplicato]

20

Voglio determinare quando effettuare un'inizializzazione non banale di una classe. Vedo due volte l'inizializzazione: costruttore e altro metodo. Voglio capire quando usarli.

Scelta 1:

Il costruttore esegue l'inizializzazione

MyClass::MyClass(Data const& data) : m_data()
{
    // does non-trivial initialization here
}

MyClass::~MyClass()
{
   // cleans up here
}

Scelta 2:

Rinvia l'inizializzazione a un metodo di inizializzazione

MyClass::MyClass() : m_data()
{}

MyClass::Initialize(Data const& data)
{
    // does non-trivial initialization here
}

MyClass::~MyClass()
{
    // cleans up here
}

Quindi per provare a rimuovere qualsiasi soggettività voglio capire quale è meglio in un paio di situazioni:

  1. Classe che incapsula una risorsa (finestra / font / una specie di handle)
  2. Classe che compone risorse per fare qualcosa (un oggetto di controllo / dominio)
  3. Classi di struttura dei dati (albero / elenco / ecc.)
  4. [Qualsiasi altra cosa tu possa pensare]

Cose da analizzare:

  1. Prestazioni
  2. Facilità d'uso da parte di altri sviluppatori
  3. In che modo incline agli errori / opportunità di bug
  4. [Qualsiasi altra cosa tu possa pensare]
posta Bob Fincheimer 12.11.2012 - 18:44
fonte

4 risposte

21

Usa sempre il costruttore a meno che non ci sia una buona ragione per non farlo. È "The C ++ Way" (tm).

Per quanto riguarda i tuoi punti da considerare:

  1. I costruttori sono sempre più o ugualmente efficienti di avere il codice all'esterno in funzioni init () separate.

  2. I costruttori tendono ad essere più facili da usare per altri sviluppatori. Senza guardare la tua fonte o i tuoi documenti, mi aspetto che new YourClass(stuff) funzioni. Dover chiamare un yourClass->init(stuff) in seguito non viene applicato dal compilatore ed è un facile errore da fare.

  3. Come per il numero 2 - un sacco di avvertimenti sui costruttori sono elaborati dai compilatori per te, in termini di ordine di inizializzazione ecc. Quando sposti le cose dai costruttori, affronti il pericolo di reinventare la ruota, a volte come un quadrato.

risposta data 12.11.2012 - 19:06
fonte
7

Idealmente, basta usare un costruttore. Di solito è una cosa brutta quando un costruttore restituisce un oggetto non proprio utilizzabile.

Tuttavia, come hanno sottolineato le persone, spesso ci sono situazioni in cui i dati necessari per inizializzare completamente un oggetto non sono disponibili al momento della costruzione. Puoi affrontare una situazione del genere usando il Pattern Builder.

Supponiamo che tu abbia una classe Foo , che richiede un'inizializzazione non banale. Crei una classe FooBuilder , che semplicemente memorizza tutti i dati necessari per inizializzare un oggetto di Foo . FooBuilder avrebbe una funzione membro (metodo aka) Foo *build() o forse Foo build() , che chiameresti quando tutti i dati sono raccolti. Potrebbe anche avere setter per vari elementi che devono essere passati al costruttore di Foo, e potrebbe fornire valori predefiniti per alcuni di questi.

Risolve il problema di "inizializzazione tardiva" senza richiedere una funzione membro initialize() . Ad esempio, se hai bisogno di creare una matrice di oggetti Foo prima di avere tutto il materiale per inizializzarli, dovresti invece creare un array di FooBuilder s. Quindi chiamerai i setter appropriati sui costruttori quando i dati saranno disponibili. Infine, quando tutti i dati sono archiviati in modo sicuro nei builder, crei un array di Foo , chiamando build() su ogni builder.

    
risposta data 12.11.2012 - 21:19
fonte
2

Un'opzione che nessuno sembra toccare è invece di costruire Init, usando un costruttore privato e una funzione di inizializzazione statica. In effetti questa è una tecnica potente perché in teoria la funzione di inizializzazione statica potrebbe costruire sottoclassi diverse basate sul contesto.

Io sceglierei l'uno o l'altro. Come altri hanno già detto, avere un costruttore seguito da una chiamata Initialize è soggetto a errori.

    
risposta data 12.11.2012 - 19:47
fonte
0

Utilizza un Init() quando devi fornire parametri al tuo oggetto che non puoi / non puoi sapere quando crei l'oggetto.

Potresti usarlo anche se la funzionalità della tua classe potrebbe richiedere del tempo per essere costruita, ad es. L'inizializzazione della riproduzione di un file video comporta l'analisi dei file, la corrispondenza e il caricamento del codec video, la corrispondenza e il caricamento del codec audio, l'acquisizione delle risorse. In questo caso, puoi suddividere la creazione in passaggi asincroni, in modo che l'app dell'utente rimanga reattiva e consenta quindi di annullare l'operazione.

    
risposta data 12.11.2012 - 19:28
fonte

Leggi altre domande sui tag