2012-01-07 12 views
16

Questa potrebbe essere una domanda con una risposta ovvia o un duplicato. Se è così, mi dispiace, lo cancellerò.Perché i costruttori di copie non sono "concatenati" come costruttori o distruttori predefiniti?

Perché i costruttori di copie non sono concatenati (come i sensori oi dors di default) cosicché prima che venga chiamato il costruttore di copie della classe derivata, viene chiamato il costruttore di copie della classe base? Con i costruttori e i distruttori di copia, vengono chiamati rispettivamente in una catena da base a derivata e da derivata a base. Perché non è questo il caso dei costruttori di copie? Ad esempio, questo codice:

class Base { 
public: 
    Base() : basedata(rand()) { } 

    Base(const Base& src) : basedata(src.basedata) { 
     cout << "Base::Base(const Base&)" << endl; 
    } 

    void printdata() { 
     cout << basedata << endl; 
    } 

private: 
    int basedata; 
}; 

class Derived : public Base { 
public: 
    Derived() { } 

    Derived(const Derived& d) { 
     cout << "Derived::Derived(const Derived&)" << endl; 
    } 
}; 


srand(time(0)); 


Derived d1;  // basedata is initialised to rand() thanks to Base::Base() 

d1.printdata(); // prints the random number 

Derived d2 = d1; // basedata is initialised to rand() again from Base::Base() 
       // Derived::Derived(const Derived&) is called but not 
       // Base::Base(const Base&) 

d2.printdata(); // prints a different random number 

Il costruttore di copia non (non può) davvero fare una copia dell'oggetto, perché Derived::Derived(const Derived&) non possono accedere basedata di cambiarlo.

C'è qualcosa di fondamentale che mi manca nei confronti dei costruttori di copie in modo che il mio modello mentale non sia corretto, o ci sia qualche motivo arcano (o non arcano) per questo progetto?

+0

@ybungalobill ha dimostrato che è possibile, e abbastanza facile. Penso che la tua domanda sia "perché non sono incatenati *** *** automaticamente?" –

+0

@AaronMcDaid sì questa è la mia domanda, ma anche questa è stata risposta sotto –

+0

@BenVoigt si, mi stavo chiedendo perché uno non scritto esplicitamente, come un costruttore scritto esplicitamente, ma questa domanda aveva già avuto risposta qualche tempo fa –

risposta

17

Il costruttore di copia non (non può) davvero fare una copia dell'oggetto, perché Derived::Derived(const Derived&) non possono accedere pdata di cambiarlo.

sicuro che può:

Derived(const Derived& d) 
    : Base(d) 
{ 
    cout << "Derived::Derived(const B&)" << endl; 
} 

Se non si specifica un costruttore della classe base nella lista di inizializzazione, il suo costruttore di default è chiamato. Se si desidera chiamare un costruttore diverso dal costruttore predefinito, è necessario specificare quale costruttore (e con quali argomenti) si desidera chiamare.

Come per perché questo è il caso: perché un costruttore di copie dovrebbe essere diverso da qualsiasi altro costruttore? Come esempio di un problema pratico:

struct Base 
{ 
    Base() { } 
    Base(Base volatile&) { } // (1) 
    Base(Base const&) { } // (2) 
}; 

struct Derived : Base 
{ 
    Derived(Derived&) { } 
}; 

Quale delle Base costruttori di copia ci si può aspettare la chiamata al costruttore Derived copia?

+0

Sembra che sia il diverso. Perché il costruttore predefinito dovrebbe essere diverso da ogni altro costruttore? –

+1

Perché può esistere un solo costruttore predefinito. –

+2

Il costruttore predefinito non è diverso dagli altri. Per tutti i costruttori, a meno che una classe base non sia specificata esplicitamente nell'elenco di inizializzazione, sarà costruita di default, così come tutti i membri che non sono specificati nell'elenco di inizializzazione saranno costruiti in modo predefinito. – DRH

3

È possibile:

Derived(const Derived& d) : Base(d) { 
    cout << "Derived::Derived(const B&)" << endl; 
} 

Questo chiama il costruttore Base copia sul Base sub-oggetto di d.

La risposta per "perché" non lo so. Ma di solito non c'è risposta. Il comitato doveva scegliere solo un'opzione o l'altra. Questo sembra più coerente con il resto della lingua, dove ad es. Derived(int x) non chiamerà automaticamente Base(x).

+0

Ah, ho dimenticato questa funzione, ma perché non è questa l'impostazione predefinita? –

+3

@Seth: Il costruttore di copie predefinito copia tutti i sottooggetti, comprese le classi di base, chiamando i loro costruttori di copie. –

+0

@BenVoigt sorry Intendevo dire perché non è il comportamento predefinito dei sistemi di autoprogrammazione, non il motivo per cui non è quello che fa il copyctor predefinito. –

2

Questo perché ogni costruzione chiama per default il costruttore di base di default:

Derived(const Derived& d) { 
    cout << "Derived::Derived(const B&)" << endl; 
} 

chiamerà Base().

Questo è definito dallo standard. Io preferisco preferirlo in questo modo piuttosto che chiamare il costruttore di copie della classe. Ovviamente puoi chiamarlo esplicitamente.

Problemi correlati