2012-03-27 7 views
18

Possiamo creare un costruttore di copia di classe virtuale in C++? Come usare?Possiamo creare un costruttore di copia di classe virtuale in C++

+4

Supponendo che si possa ... quale tipo deve essere inviata la chiamata del costruttore? –

+1

Duplicato di http://stackoverflow.com/questions/733360/why-do-we-not-have-a-virtual-constructor-in-c –

+0

@ DavidRodríguez-dribeas: Questo è un buon punto. Penso che dovrebbe essere una risposta, in quanto spiega anche la motivazione – Nawaz

risposta

18

No, non è possibile, i costruttori non possono essere virtuali.

C++ 03 - 12.1 Costruttori

4) Un costruttore non deve essere virtual (10.3) o static (9.4). [...]

Se avete bisogno di qualcosa di simile, potete cercare l'idioma del costruttore virtuale here.

+0

il tuo link è vietato – Arne

+0

@Arne grazie per averlo indicato. Ho aggiornato il link. –

+0

grazie per l'aggiornamento. – Arne

0

Mai, non sarà possibile in C++.

1

No. C++ essendo un linguaggio tipizzato statico, non ha alcun significato per il compilatore C++ per creare un oggetto in modo polimorfico. Il compilatore deve essere consapevole del tipo di classe per creare l'oggetto. In altre parole, il tipo di oggetto da creare è una decisione in fase di compilazione dalla prospettiva del compilatore C++. Se rendiamo virtuale il costruttore, il compilatore segnala un errore.

+1

Non completamente vero, vedere il modello di fabbrica astratto. –

5

No, non è possibile.

Inoltre, l'intero concetto non ha senso. Le funzioni virtuali sono funzioni che vengono inviate in base al valore di un oggetto (il tipo dinamico dell'oggetto). Quando viene chiamato un costruttore, l'oggetto non ha ancora un valore (perché non è stato ancora creato). Pertanto, non è possibile che si verifichi alcuna spedizione virtuale.

Pensaci. Quale semantica avrebbe un simile costruttore?

1

Non è possibile perché la memoria viene allocata prima che il costruttore venga chiamato in base alle dimensioni del nuovo tipo e non all'operando di copia. E se funzionasse, sarebbe un caso speciale quello del polimorfismo invertito per un numero di costrutti linguistici.

Ma questo non significa che non possa essere fatto con un po 'di magia C++. :)

Ci sono alcuni casi in cui è incredibilmente utile, Serializzare classi non POD per esempio. In questo esempio viene creato un costruttore di copia virtuale che funziona utilizzando il posizionamento nuovo.

Avvertenza: questo è un esempio che può aiutare alcuni utenti con problemi specifici. Non farlo nel codice di scopo generale. Arresto anomalo se la memoria allocata per la nuova classe è inferiore alla classe derivata. Il modo migliore (e il solo) sicuro per usarlo è se gestisci la tua memoria di classe e usi il posizionamento nuovo.

class VirtualBase 
{ 
public: 
    VirtualBase() {} 
    virtual ~VirtualBase() {} 

    VirtualBase(const VirtualBase& copy) 
    { 
     copy.VirtualPlacementCopyConstructor(this); 
    } 

    virtual void VirtualPlacementCopyConstructor(void*) const {} 
}; 

class Derived :: public VirtualBase 
{ 
public: 
    ... 

    Derived(const Derived& copy) : ... don't call baseclass and make an infinite loop 
    { 
    } 

protected: 
    void VirtualPlacementCopyConstructor(void* place) const 
    { 
     new (place) Derived(*this); 
    } 
}; 
+0

Questo non verrà compilato, anche se lo aggiustate per farlo compilare, l'implementazione è piuttosto rotta. Tutti i membri di "Derived" subiranno una doppia inizializzazione. Questo potrebbe accadere per funzionare con alcuni tipi semplici, ma risultati chiaramente in un comportamento indefinito. Il "costruttore" dovrebbe essere "void VirtualPlacementCopyConstructor (VirtualBase * place) const {auto d = dynamic_cast (luogo); if (d) {d-> ~ Derived(); nuovo (d) derivato (* questo); }} ' –

+0

Dovrebbe essere ora ovvio qual è il problema: il' VirtualPlacementCopyConstructor' è invocato troppo presto, quando il tipo della classe copiata non è ancora 'Derivato '. Quindi il distruttore non farà la cosa giusta, e otterrai un comportamento indefinito in abbondanza. Se sostituisci 'dynamic_cast' con' static_cast', le cose funzioneranno per i tipi di POD, e questo è tutto. Non appena aggiungi, ad es. un membro 'std :: string', la roba si spezzerà (peggio ancora: non si romperà sempre, quindi ti strapperai i capelli). –

Problemi correlati