2009-05-29 14 views

risposta

202

Per i membri della classe POD, non fa differenza, è solo una questione di stile. Per i membri della classe che sono classi, evita una chiamata non necessaria a un costruttore predefinito. Si consideri:

class A 
{ 
public: 
    A() { x = 0; } 
    A(int x_) { x = x_; } 
    int x; 
}; 

class B 
{ 
public: 
    B() 
    { 
     a.x = 3; 
    } 
private: 
    A a; 
}; 

In questo caso, il costruttore di B chiamerà il costruttore predefinito per A, e poi inizializzare a.x a 3. Un modo migliore sarebbe per B 's costruttore di chiamare direttamente A' costruttore s in la lista di inizializzazione:

B() 
    : a(3) 
{ 
} 

Questo sarebbe solo chiamare s' AA(int) di costruzione e non il suo costruttore di default. In questo esempio, la differenza è trascurabile, ma immaginate se il costruttore predefinito di A ne abbia fatto di più, ad esempio allocando memoria o aprendo file. Non vorrai farlo inutilmente.

Inoltre, se una classe non ha un costruttore di default, o si dispone di una variabile const membro, è necessario utilizzare una lista di inizializzazione:

class A 
{ 
public: 
    A(int x_) { x = x_; } 
    int x; 
} 

class B 
{ 
public: 
    B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list; 
    {     // it is an error not to do so 
    } 
private: 
    A a; 
    const int y; 
}; 
+0

membri della classe che sono le classi possono essere POD, troppo –

+1

un must anche per importante caso di un riferimento – 4pie0

+1

Perché non usare "una (3);" o "a = A (3);" nel corpo del costruttore predefinito di B? – Sergey

34

A parte i motivi di prestazioni di cui sopra, se la tua classe memorizza i riferimenti agli oggetti passati come parametri del costruttore o la tua classe ha variabili const, quindi non hai altra scelta che usare gli elenchi di inizializzatori.

+6

Lo stesso vale per i membri const che credo. –

6

Accanto ai problemi di prestazioni, ce n'è un altro molto importante che chiamerei manutenibilità ed estendibilità del codice.

Se un T è POD e si inizia a preferire l'elenco di inizializzazione, allora se T una volta passerà a un tipo non POD, non sarà necessario modificare nulla attorno all'inizializzazione per evitare chiamate di costruttori non necessarie perché è già ottimizzato .

Se il tipo T ha un costruttore predefinito e uno o più costruttori definiti dall'utente e una volta si decide di rimuovere o nascondere quello predefinito, se è stato utilizzato l'elenco di inizializzazione, non è necessario aggiornare il codice se l'utente - costruttori definiti perché sono già implementati correttamente.

Stessa cosa con i membri o membri di riferimento const, diciamo inizialmente T è definito come segue:

struct T 
{ 
    T() { a = 5; } 
private: 
    int a; 
}; 

Successivamente, si decide di qualificare un come const, se si usa la lista di inizializzazione fin dall'inizio, allora questo era una singola linea cambiamento, ma avente la T definito come sopra, ma richiede anche scavare la definizione costruttore per rimuovere assegnazione:

struct T 
{ 
    T() : a(5) {} // 2. that requires changes here too 
private: 
    const int a; // 1. one line change 
}; 

non è un segreto che la manutenzione è molto più facile e meno soggetto a errori se il codice era scritto non da un "codice monke" "ma da un ingegnere che prende decisioni basate su una considerazione più profonda su ciò che sta facendo.

+2

+1 per "code monkey" – Invictus

4

Prima di eseguire il corpo del costruttore, vengono richiamati tutti i costruttori per la classe padre e quindi per i relativi campi. Per impostazione predefinita, vengono invocati i costruttori senza argomento. Gli elenchi di inizializzazione consentono di scegliere quale costruttore viene chiamato e quali argomenti riceve il costruttore.

Se si dispone di un riferimento o un campo const o se una delle classi utilizzate non ha un costruttore predefinito, è necessario utilizzare un elenco di inizializzazione.

2
// Without Initializer List 
class MyClass { 
    Type variable; 
public: 
    MyClass(Type a) { // Assume that Type is an already 
        // declared class and it has appropriate 
        // constructors and operators 
     variable = a; 
    } 
}; 

Qui compilatore segue seguenti passi per creare un oggetto di tipo MiaClasse costruttore
1. di tipo viene chiamato per primo per “a”.
2. L'operatore di assegnazione di “Tipo” è chiamato all'interno del corpo di MyClass() per assegnare

variable = a; 
  1. E infine distruttore “Tipo” si chiama per "a" dal momento che va fuori dal campo di applicazione.

    Consideriamo ora lo stesso codice con MyClass() costruttore con lista di inizializzazione

    // With Initializer List 
    class MyClass { 
    Type variable; 
    public: 
    MyClass(Type a):variable(a) { // Assume that Type is an already 
           // declared class and it has appropriate 
           // constructors and operators 
    } 
    }; 
    

    Con la lista di inizializzazione, seguendo i passi sono seguiti da compilatore:

    1. Copia costruttore della classe “Tipo” è chiamato per inizializzare: variabile (a). Gli argomenti nella lista di inizializzazione sono usati per copiare direttamente la "variabile" del costrutto.
    2. Il distruttore di "Tipo" viene chiamato per "a" poiché non rientra nell'ambito.
+2

Sebbene questo snippet di codice possa risolvere la domanda, anche una spiegazione del codice aiuta a migliorare la qualità del post. Ricorda che stai rispondendo alla domanda per i lettori in futuro, e queste persone potrebbero non conoscere le ragioni del tuo suggerimento sul codice. Cerca anche di non affollare il tuo codice con commenti esplicativi, questo riduce la leggibilità sia del codice che delle spiegazioni! http://meta.stackexchange.com/q/114762/308249 – davejal

+2

Per favore, scrivi la tua comprensione o condividi semplicemente il link alla fonte originale (qui, geeksforgeeks.com) invece di limitarti a copiarlo. – yuvi

10
  1. inizializzazione della classe base

Una ragione importante per l'utilizzo lista di inizializzazione del costruttore che non è menzionato nelle risposte qui è l'inizializzazione della classe di base.

Secondo l'ordine di costruzione, la classe base deve essere costruita prima della classe bambino. Senza l'elenco di inizializzatore del costruttore, questo è possibile se la classe base ha un costruttore predefinito che verrà chiamato appena prima di entrare nel costruttore della classe figlio.

Tuttavia, se la classe base ha solo un costruttore con parametri, è necessario utilizzare l'elenco di inizializzatore del costruttore per garantire che la classe base sia inizializzata prima della classe figlio.

  1. inizializzazione di suboggetti che hanno solo i costruttori con parametri

  2. efficienza

Uso lista di inizializzazione del costruttore, si inizializza i tuoi membri di dati a lo stato esatto di cui hai bisogno nel tuo codice invece di inizializzarlo al loro stato predefinito &, quindi cambiare il loro stato in quello che ti serve il tuo codice.

  1. inizializzazione dati membro const non statici

Se i membri di dati const non statici nella tua classe hanno costruttori di default & non si utilizza la lista di inizializzazione del costruttore , non sarà possibile inizializzarli allo stato previsto poiché verranno inizializzati allo stato predefinito.

  1. inizializzazione dei membri di dati di riferimento

membri di dati di riferimento deve essere inizializzata quando compilatore entra costruttore come riferimenti non possono essere dichiarati solo & inizializzato in seguito. Questo è possibile solo con l'elenco di inizializzatore del costruttore.

0

Sintassi:

class Sample 
    { 
    public: 
     int Sam_x; 
     int Sam_y; 

    Sample(): Sam_x(1), Sam_y(2)  /* Classname: Initialization List */ 
    { 
      // Constructor body 
    } 
    }; 

Necessità di lista di inizializzazione:

class Sample 
{ 
    public: 
     int Sam_x; 
     int Sam_y; 

    Sample()  */* Object and variables are created - i.e.:declaration of variables */* 
    { // Constructor body starts 

     Sam_x = 1;  */* Defining a value to the variable */* 
     Sam_y = 2; 

    } // Constructor body ends 
    }; 

nel programma di cui sopra, quando viene eseguito il costruttore della classe, Sam_x e Sam_y sono creati. Quindi nel corpo del costruttore, vengono definite le variabili dei dati membro.

I casi d'uso:

  1. Const e di riferimento variabili in una classe

In C, le variabili devono essere definiti durante la creazione. allo stesso modo in C++, dobbiamo inizializzare la variabile Const e Reference durante la creazione dell'oggetto usando l'elenco di inizializzazione. se eseguiamo l'inizializzazione dopo la creazione dell'oggetto (nel corpo del costruttore interno), otterremo l'errore del tempo di compilazione.

  1. oggetti membro di Sample1 (di base) di classe che non hanno costruttore di default

    class Sample1 
    { 
        int i; 
        public: 
        Sample1 (int temp) 
        { 
         i = temp; 
        } 
    }; 
    
        // Class Sample2 contains object of Sample1 
    class Sample2 
    { 
        Sample1 a; 
        public: 
        Sample2 (int x): a(x)  /* Initializer list must be used */ 
        { 
    
        } 
    }; 
    

Mentre la creazione di oggetti per la classe derivata che internamente chiamate classe derivata costruttore e chiama costruttore della classe base (predefinito). se la classe base non ha un costruttore predefinito, l'utente riceverà un errore in fase di compilazione.Per evitare, dobbiamo avere uno

1. Default constructor of Sample1 class 
2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program) 
  1. nome del parametro e dati utente

    Classe di costruttore di una classe sono gli stessi:

    class Sample3 { 
        int i;   /* Member variable name : i */ 
        public: 
        Sample3 (int i) /* Local variable name : i */ 
        { 
         i = i; 
         print(i); /* Local variable: Prints the correct value which we passed in constructor */ 
        } 
        int getI() const 
        { 
         print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/ 
         return i; 
        } 
    }; 
    

Come tutti sapere, la variabile locale ha la massima priorità della variabile globale se entrambe le variabili hanno lo stesso nome. In questo caso, il programma considera il valore "i" {variabile sia destra che sinistra. cioè: i = i} come variabile locale nel costruttore Sample3() e la variabile membro della classe (i) ha precedenza. Per evitare, dobbiamo utilizzare sia

1. Initialization list 
    2. this operator. 
Problemi correlati