Domanda

Perché C ++ non ha un costruttore virtuale?

Nessuna soluzione corretta

Altri suggerimenti

sentire dalla bocca :) del cavallo.

Da C di Bjarne Stroustrup ++ stile e la tecnica FAQ Perché non abbiamo costruttori virtuali?

  

Una chiamata virtuale è un meccanismo per ottenere il lavoro fatto dato parziale   informazione. In particolare, "virtuale" ci permette di chiamare una funzione   conoscendo solo qualsiasi interfaccia e non il tipo esatto dell'oggetto. Per   creare un oggetto avete bisogno di informazioni complete. In particolare, è   necessario conoscere il tipo esatto di ciò che si vuole creare. Di conseguenza,   una "chiamata a un costruttore" non può essere virtuale.

La voce FAQ continua a fornire il codice di un modo per raggiungere questo fine, senza un costruttore virtuale.

Le funzioni virtuali fondamentalmente forniscono comportamento polimorfico. Cioè, quando si lavora con un oggetto il cui tipo dinamico è diverso statico (tempo di compilazione) con il quale si riferisce a, fornisce un comportamento che è appropriato per la reale tipo di oggetto anziché il tipo statico dell'oggetto.

Ora provate ad applicare questo tipo di comportamento a un costruttore. Quando si costruisce un oggetto del tipo statico è sempre lo stesso tipo di oggetto reale in quanto:

  

Per costruire un oggetto, un costruttore ha bisogno il tipo esatto dell'oggetto è di creare [...] Inoltre [...] non si può avere un puntatore a un costruttore

(Bjarne Stroustup (P424 Il C ++ Programming Language SE))

A differenza di linguaggi orientati agli oggetti come ad esempio Smalltalk o Python, in cui il costruttore è un metodo virtuale dell'oggetto che rappresenta la classe (il che significa che non è necessario il GoF astratto fabbrica modello , come si può passare l'oggetto che rappresenta la classe intorno invece di fare il proprio), C ++ è un linguaggio basato di classe, e non ha oggetti che rappresentano ogni dei costrutti del linguaggio. La classe non esiste come un oggetto in fase di esecuzione, quindi non si può chiamare un metodo virtuale su di esso.

Questo si adatta con la filosofia 'non si paga per ciò che non si usa', anche se tutti i progetti di grandi dimensioni C ++ che ho visto ha finito per attuare una qualche forma di fabbrica astratta o di riflessione.

due motivi che mi vengono in mente:

ragione tecnica

L'oggetto esiste solo dopo l'ordine ends.In costruttore per il costruttore, viene inviato utilizzando la tabella virtuale, ci deve essere un oggetto esistente con un puntatore alla tabella virtuale, ma come può un puntatore alla tabella virtuale esistere se l'oggetto ancora non esiste? :)

ragione logica

Si utilizza la parola chiave virtuale quando si vuole dichiarare un comportamento un po 'polimorfico. Ma non c'è nulla polimorfica con i costruttori, i costruttori di lavoro in C ++ è quello di mettere semplicemente un dato oggetto nella memoria. Dal momento che le tabelle virtuali (e polimorfismo in generale) sono tutti di comportamento polimorfico piuttosto su dati polimorfici, Non v'è alcun senso di dichiarare un costruttore virtuale.

Lo facciamo, non è solo un costruttore: -)

struct A {
  virtual ~A() {}
  virtual A * Clone() { return new A; }
};

struct B : public A {
  virtual A * Clone() { return new B; }
};

int main() {

   A * a1 = new B;
   A * a2 = a1->Clone();    // virtual construction
   delete a2;
   delete a1;
}

ragioni semantiche parte, non c'è vtable fino a dopo l'oggetto viene costruito, rendendo così una designazione virtuale inutile.

Sommario : il ++ standard C potrebbero specificare una notazione e il comportamento per "costruttore virtuale" s che è ragionevolmente intuitivo e non troppo difficile per i compilatori a sostenere, ma perché fare un cambiamento standard per questo in particolare quando il funzionalità possono già essere pulito implementato usando create() / clone() (vedi sotto)? Non è quasi come utile come molti proposta altra lingua in cantiere.

Discussione

Diamo postulare un meccanismo di "costruttore virtuale":

Base* p = new Derived(...);
Base* p2 = new p->Base();  // possible syntax???

In quanto precede, la prima linea costruisce un oggetto Derived, così tabella di invio virtuale di *p può ragionevolmente fornire un "costruttore virtuale" da utilizzare nella seconda riga. (Decine di risposte in questa pagina affermando "l'oggetto non esiste ancora costruzione in modo virtuale è impossibile" sono inutilmente miope focalizzate sull'oggetto to-be-costruito.)

La seconda riga postula la new p->Base() notazione per richiedere allocazione dinamica e predefinito costruzione di un altro oggetto Derived.

Note:

  • il compilatore deve orchestrare l'allocazione della memoria prima di chiamare il costruttore - costruttori normalmente supportano (informalmente "stack") allocazione automatica, static (per l'ambito / namespace globale e oggetti classe- / funzione-static), e dinamica (informalmente "cumulo") quando si usa new

    • la dimensione dell'oggetto da essere costruito p->Base() non possono essere generalmente noto al momento della compilazione, quindi allocazione dinamica è l'unico approccio sensato

  • per l'allocazione dinamica deve restituire un puntatore in modo memoria può essere deleted successivamente.

  • la notazione postulato esplicitamente elenca new sottolineare l'allocazione dinamica e il tipo di risultato puntatore.

Il compilatore avrebbe bisogno di:

  • scoprire la quantità di memoria necessaria Derived, chiamando una funzione virtual sizeof implicita o disporre di tali informazioni tramite RTTI
  • chiamata operator new(size_t) per allocare la memoria
  • invocare Derived() con il posizionamento new.

o

  • creare una voce vtable in più per una funzione che combina l'allocazione dinamica e la costruzione

Quindi - non sembra insormontabile per specificare e implementare costruttori virtuali, ma la domanda da un milione di dollari è: come sarebbe meglio di ciò che è possibile utilizzare le funzioni linguistiche esistenti C ++ ...? Personalmente, non vedo alcun beneficio sulla soluzione qui di seguito.


`clone ()` e `create ()`

Il C ++ FAQ documenta un "costruttore virtuale" idioma , contenente virtual create() e clone() metodi per default-costrutto o copia costruire un nuovo oggetto dinamicamente allocato:

class Shape {
  public:
    virtual ~Shape() { } // A virtual destructor
    virtual void draw() = 0; // A pure virtual function
    virtual void move() = 0;
    // ...
    virtual Shape* clone() const = 0; // Uses the copy constructor
    virtual Shape* create() const = 0; // Uses the default constructor
};
class Circle : public Shape {
  public:
    Circle* clone() const; // Covariant Return Types; see below
    Circle* create() const; // Covariant Return Types; see below
    // ...
};
Circle* Circle::clone() const { return new Circle(*this); }
Circle* Circle::create() const { return new Circle(); }

E 'anche possibile cambiare o sovraccarico create() di accettare argomenti, anche se per abbinare firma di funzione virtual la base di classe / dell'interfaccia, argomenti per le sostituzioni devono corrispondere esattamente uno dei sovraccarichi classe di base. Wiesimo queste strutture forniti dall'utente esplicite, è facile aggiungere la registrazione, la strumentazione, modificare l'allocazione della memoria, ecc ..

È possibile trovare un esempio e la ragione tecnica per cui non è consentito in risposta l' @stefan. Ora una risposta logica a questa domanda secondo me è:

L'uso principale di parola chiave virtuale è quello di consentire un comportamento polimorfico quando non sappiamo che tipo di oggetto del puntatore alla classe base punterà.

Ma pensare a questo è il modo più primitivo, per l'utilizzo di funzionalità virtuale è necessario un puntatore. E cosa fa un puntatore richiede? Un oggetto a punto da! (Considerando caso per la corretta esecuzione del programma)

Quindi, abbiamo praticamente bisogno di un oggetto che esiste già da qualche parte nella memoria (non ci occupiamo di come è stata allocata la memoria, può essere al momento della compilazione o uno runtime) in modo che il nostro puntatore può puntare correttamente a quell'oggetto.

Ora, pensare alla situazione circa il momento in cui l'oggetto della classe da rilevare che viene assegnato po 'di memoria! -> Il suo costruttore verrà chiamato automaticamente in quel istanza stessa

Così possiamo vedere che non abbiamo effettivamente bisogno di preoccuparsi per il costruttore essendo virtuale, perché in nessuno dei casi che si desidera utilizzare un comportamento polimorfico nostro costruttore sarebbe già stato eseguito rendere il nostro oggetto pronto per l'uso!

Anche se il concetto di costruttori virtuali non si adatta bene dato che tipo di oggetto è pre-requisito per la creazione di oggetti, la sua non è completamente over-governata.

modello di progettazione 'metodo factory' di GOF fa uso del 'concept' del costruttore virtuale, che è maneggevole in certe situazioni di progetto.

Le funzioni virtuali in C ++ sono un'implementazione di run-time il polimorfismo, e faranno la funzione prevalente. In genere, la parola chiave virtual viene utilizzato in C ++ quando si ha bisogno comportamento dinamico. Essa funziona solo quando esiste oggetto. Mentre i costruttori sono utilizzati per creare gli oggetti. Costruttori saranno chiamati al momento della creazione dell'oggetto.

Quindi, se si crea il costruttore come virtual, secondo la definizione parola chiave virtuale, dovrebbe avere oggetto esistente da utilizzare, ma costruttore viene utilizzato per creare l'oggetto, quindi questo caso non potrà mai esistere. Quindi non si dovrebbe usare il costruttore come virtuale.

Quindi, se proviamo a dichiarare compilatore costruttore virtuale genera un errore:

  

I costruttori non possono essere dichiarate virtuale

Quando le persone chiedono una domanda come questa, mi piace pensare a me stesso "cosa succederebbe se questo fosse effettivamente possibile?" Io non so davvero che cosa questo significherebbe, ma credo che sarebbe avere a che fare con l'essere in grado di sostituire l'implementazione costruttore in base al tipo dinamico dell'oggetto in fase di creazione.

Vedo una serie di potenziali problemi con questo. Per prima cosa, la classe derivata non sarà pienamente realizzato al momento il costruttore virtuale è chiamato, quindi non ci sono potenziali problemi con l'implementazione.

In secondo luogo, che cosa accadrebbe nel caso di ereditarietà multipla? Il tuo costruttore virtuale sarebbe stato chiamato più volte, presumibilmente, si avrebbe quindi bisogno di avere qualche modo di sapere quale era stato chiamato.

In terzo luogo, in generale, al momento della costruzione, l'oggetto non ha la tabella virtuale completato, questo significa che richiede un sostanziale modifica della specifica di linguaggio per tener conto del fatto che il tipo dinamico dell'oggetto sarebbe noto al momento della costruzione. Questo sarebbe poi consentire al costruttore della classe base a forse chiamare altre funzioni virtuali in fase di costruzione, con un tipo di classe dinamica non è completamente costruito.

Infine, come qualcun altro ha fatto notare è possibile implementare una sorta di costruttore virtuale utilizzando "creare" o "init" tipo funzioni statiche che in fondo fanno la stessa cosa come costruttore virtuale farebbe.

funzioni virtuali sono utilizzate per invocare funzioni a seconda del tipo di oggetto puntato dal puntatore, e non il tipo di puntatore stesso. Ma un costruttore non è "invocata". Si chiama solo una volta quando un oggetto viene dichiarato. Quindi, un costruttore non può essere virtuale in C ++.

Non si dovrebbe chiamare funzione virtuale all'interno del vostro costruttore sia. Vedere: http://www.artima.com/cppsource/nevercall.html

Inoltre non sono sicuro che si ha realmente bisogno di un costruttore virtuale. È possibile ottenere la costruzione polimorfico senza di essa:. È possibile scrivere una funzione che costruirà l'oggetto in base ai parametri necessari

A virtual-tavolo (vtable) è realizzato per ogni Classe avente uno o più "virtuali funzioni. Ogni volta che viene creato un oggetto di tale classe, contiene un 'virtuale puntatore' che punta alla base della corrispondente vtable. Ogni volta che c'è una chiamata di funzione virtuale, il vtable viene utilizzato per risolvere l'indirizzo della funzione.     Costruttore non può essere virtuale, perché quando si esegue costruttore di una classe non c'è vtable nella memoria, mezzi di alcun puntatore virtuale ancora definito. Quindi il costruttore deve sempre essere non virtuale.

Non posso semplicemente dire che come .. Non possiamo ereditare i costruttori. Quindi non v'è alcun punto dichiarandoli virtuale perché il virtuale fornisce polimorfismo.

Il meccanismo virtuale funziona solo quando si dispone di un puntatore alla classe base a un oggetto della classe derivata. Costruzione ha il proprio le regole per la convocazione di costruttori della classe base, classe base in fondo al derivato. Come potrebbe un costruttore virtuale essere utile o chiamato? Non so quali altre lingue fare, ma non riesco a capire come un costruttore virtuale potrebbe essere utile o addirittura implementato. Costruzione deve aver luogo per il meccanismo virtuale avere un senso e costruzione deve anche aver luogo per le strutture vtable per cui sono stati creati fornisce la meccanica del comportamento polimorfico.

C'è un motivo molto semplice:. Costruttori sono funzioni in modo efficace statici, e in C ++ alcuna funzione statica può essere virtuale

Se si dispone di molta esperienza con C ++, si sa tutto sulla differenza tra funzioni statiche e registri. funzioni statiche sono associate con la classe, non gli oggetti (istanze), in modo che non vedono un puntatore "this". Solo le funzioni membro possono essere virtuale, perché il vtable- la tabella nascosta di puntatori a funzione che rende 'virtuale' lavoro-è in realtà un membro di dati di ogni oggetto.

Ora, qual è il lavoro del costruttore? E 'nel nome- un costruttore "T" inizializza oggetti T come sono allocate. Questo preclude automaticamente che sia una funzione di membro! Un oggetto deve esistere prima che ha un puntatore "this" e quindi una vtable. Ciò significa che, anche se i costruttori di lingue trattate come funzioni ordinarie (non, per ragioni connesse non voglio entrare in), avrebbero dovuto essere funzioni membro statiche.

Un ottimo modo di vedere questo è quello di guardare il modello di "Factory", in particolare le funzioni di fabbrica. Fanno quello che stai dopo, e si noterà che se la classe T ha un metodo factory, è sempre statico. Deve essere.

costruttore virtuale C ++ non è esempio possible.For non è possibile contrassegnare un costruttore come virtual.Try questo codice

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        virtual aClass()
        {   
        }  
};
int main()
{
    aClass a; 
}

Essa provoca un codice error.This sta tentando di dichiarare un costruttore come virtuale. Ora cerchiamo di capire perché usiamo parole chiave virtuale. parola chiave virtuale viene utilizzata per fornire fase di esecuzione il polimorfismo. Per esempio provare questo codice.

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        aClass()
        {
            cout<<"aClass contructor\n";
        }
        ~aClass()
        {
            cout<<"aClass destructor\n";
        }

};
class anotherClass:public aClass
{

    public:
        anotherClass()
        {
            cout<<"anotherClass Constructor\n";
        }
        ~anotherClass()
        {
            cout<<"anotherClass destructor\n";
        }

};
int main()
{
    aClass* a;
    a=new anotherClass;
    delete a;   
    getchar(); 
}

In a=new anotherClass; principale alloca una memoria per anotherClass in un a puntatore dichiarato come tipo di aClass.This provoca sia il costruttore (In aClass e anotherClass) per chiamare automatically.So non abbiamo bisogno di segnare costruttore come virtual.Because quando un oggetto viene creato deve seguire la catena di creazione (cioè prima della base e quindi le classi derivate). Ma quando si tenta di eliminare un delete a; provoca chiamare solo la base destructor.So dobbiamo gestire il distruttore tramite parola chiave virtuale. costruttore Quindi virtuale non è possibile, ma distruttore virtuale è Ringraziamenti

Se si pensa logicamente su come i costruttori di lavoro e quale sia il significato / uso di una funzione virtuale è in C ++, allora vi renderete conto che un costruttore virtuale non avrebbe senso in C ++. Dichiarare qualcosa di virtuale in C ++ significa che può essere sostituito da una sottoclasse della classe corrente, tuttavia il costruttore viene chiamato quando il obiettato si crea, in quel momento non si può essere la creazione di una sottoclasse della classe, è necessario essere la creazione della classe quindi non ci sarebbe mai stata alcuna necessità di dichiarare un costruttore virtuale.

E un altro motivo è che i costruttori hanno lo stesso nome come il suo nome della classe e se noi dichiariamo costruttore come virtuale, allora dovrebbe essere ridefinito nella sua classe derivata con lo stesso nome, ma non si può avere lo stesso nome di due classi. Quindi non è possibile avere un costruttore virtuale.

  1. Quando un costruttore viene richiamato, anche se non v'è alcun oggetto creato fino a quel punto, sappiamo ancora il tipo di oggetto che sta andando essere creato perché il costruttore specifica della classe a cui appartiene l'oggetto è già stato chiamato.

    parola Virtual associata con una funzione significa il funzione di un particolare tipo di oggetto è gonna essere chiamato.

    Quindi, il mio pensiero dice che non c'è bisogno di fare il costruttore virtuale perché già il costruttore desiderato cui oggetto sta andando essere creato è stato invocato e fare costruttore virtuale è solo una cosa ridondante da fare perché il object costruttore specifica è già stato invocato e questo è uguale a chiamare funzione specifica di classe , che si ottiene attraverso la parola chiave virtuale.

    Sebbene l'implementazione interna non permetterà costruttore virtuale per vptr e ragioni connesse vtable.

  1. Un altro motivo è che il C ++ è un linguaggio a tipizzazione statica e abbiamo bisogno di conoscere il tipo di una variabile a tempo di compilazione.

    Il compilatore deve essere a conoscenza del tipo di classe per creare l'oggetto. Il tipo di oggetto da creare è una decisione in fase di compilazione.

    Se facciamo il costruttore virtuale, allora vuol dire che non abbiamo bisogno di conoscere il tipo di oggetto al momento della compilazione (che è quello che la funzione virtuali forniscono. Non abbiamo bisogno di conoscere l'oggetto reale e solo bisogno del puntatore base per puntare un oggetto vero e proprio chiamare le funzioni virtuali degli oggetti a punta senza conoscere il tipo di oggetto) e, se non conosciamo il tipo di oggetto al momento della compilazione, allora è contro i linguaggi staticamente tipizzati. E quindi, in fase di esecuzione il polimorfismo non può essere raggiunto.

    Quindi, costruttore non verrà chiamato senza conoscere il tipo dell'oggetto a tempo di compilazione. E così l'idea di fare un costruttore virtuale non riesce.

Il Vpointer viene creata al momento della creazione dell'oggetto. vpointer esiste solito prima della creazione dell'oggetto. quindi non c'è nessun punto di rendere il costruttore come virtuale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top