2014-04-23 27 views
5

In C++, un aggregato è (tratto da 8.5.1p1 delle specifiche linguaggio)Gli aggregati C++ non hanno funzioni virtuali?

un array o una classe (Clausola 9) senza costruttori forniti dall'utente (12.1), non privata o non protetta membri statici (clausola 11), nessuna classe base (clausola 10) e nessuna funzione virtuale (10.3).

Quindi, #1 non è un aggregato, ma #2 è un aggregato. Perché lo #1 non è un aggregato?

struct A { virtual void bark() { } int a; }; // #1 
struct B { A b; }; // #2 
+3

"[..] e nessuna funzione virtuale (10.3)"? – MrDuk

+0

Il tuo citare "nessuna funzione virtuale" ci dice che è un aggregato. – harper

+0

@MrDuk Sì, posso verificare che questa sia l'ultima parte del testo che ho citato. O volevi fare una domanda diversa? –

risposta

5

Perché # 1 non è un aswell aggregata?

Perché la definizione standard di aggregati dice che non lo è. La definizione dice che la classe non può avere funzioni virtuali se deve essere considerata un tipo aggregato. Questo è tutto. Questa è la risposta del "capitano ovvio".

Poiché hai citato la definizione standard (e leggerla, presumo), lo sai già, quindi devo presumere che ciò che stai chiedendo è se ci sia una ragione fondamentale per cui una classe con funzioni virtuali non può essere un aggregato genere.

Ovviamente, una classe con funzioni virtuali deve avere il puntatore della tabella virtuale (o altro meccanismo) inizializzato come parte del costruttore generato dal compilatore. E l'unica cosa che gli aggregati forniscono realmente (oltre a servire come una definizione di base per i POD e simili) è la capacità di eseguire un'inizializzazione con rinforzo dei suoi membri di dati. Non vedo alcun motivo per cui il compilatore non può semplicemente consentire la sintassi di inizializzazione con rinforzo ricurvo durante l'inizializzazione del puntatore della tabella virtuale.

Per quanto riguarda lo B, può essere un aggregato perché l'inizializzazione del controvento è possibile fintanto che esiste un modo per costruire i membri dati da qualsiasi cosa sia fornita (o non fornita) nell'elenco di inizializzazione, vale a dire , ha bisogno che ogni membro di dati abbia un costruttore predefinito (compilatore o non) di copia, modifica o spostamento. Ricorda, la definizione di aggregati è shallow in contrapposizione a ricorsiva come le definizioni POD (banale, std-layout), il che significa che solo la classe di primo livello ha quelle restrizioni, non i suoi sotto-oggetti.

La definizione di aggregati è ovviamente molto simile alle restrizioni C struct e l'inizializzazione delle parentesi graffe per le strutture è ovviamente anche una caratteristica riportata da C. Credo che per ragioni storiche, la definizione di aggregati sia stata costruita in modo tale che riflette le strutture di C, e non per ragioni di ciò che è o non è possibile fare per il compilatore.

Sarei certamente dell'opinione che non ci sia una buona ragione per la restrizione sugli aggregati di non avere funzioni virtuali. Forse una proposta dovrebbe essere presentata al comitato standard per rimuovere questa restrizione (in quanto non romperebbe alcun codice esistente). Soprattutto ora, con la sintassi di inizializzazione unificata, gli aggregati non sono altro che classi in cui il compilatore può generare un costruttore con tutti i membri dati come parametri (con i valori predefiniti come oggetti costruiti di default). L'unico altro scopo per gli aggregati è di raggruppare alcune delle restrizioni che si applicano alle classi POD (banale, layout standard, ecc.), Per le quali la restrizione a non avere funzioni virtuali è giustificata (AFAIK), ma questo è solo un questione di spostare tale restrizione sui POD.

+1

* Ovviamente, una classe con funzioni virtuali deve avere il puntatore della tabella virtuale inizializzato come parte del costruttore generato dal compilatore. * => Vorrei sottolineare che lo standard C++ non richiede l'uso di una tabella virtuale, e quindi un virtuale puntatore del tavolo. È, infatti, un'implementazione molto comune del meccanismo di invio "virtuale", e come tale pesa su tutte le decisioni che riguardano la gestione virtuale, ma è * solo * un dettaglio di implementazione. –

+0

@MatthieuM. Certo, è vero. Ma la logica è la stessa indipendentemente dai dettagli di implementazione. Se il compilatore può generare un costruttore predefinito (o un costruttore predefinito con inizializzatori di membri in classe) per qualsiasi classe (incluse le funzioni virtuali), dovrebbe essere in grado di generare un costruttore da utilizzare con la sintassi di inizializzazione del brace per aggregati. Penso che la restrizione della funzione virtuale sia semplicemente fuori posto nello standard, dovrebbe essere solo per le definizioni POD, non per gli aggregati. –

+1

POD-ness ha richiesto l'aggregazione in C++ 03 (C++ 03 [classe]/4), che non è più il caso.I POD sono definiti in modo ricorsivo * banale * e * standard-layout * (C++ 11 [classe]/10), nessuno dei quali richiede di essere un aggregato. È possibile che una classe/unione sia sia un POD che un aggregato, ma non richiesto. Rimozione della restrizione sulle funzioni virtuali dagli aggregati non richiederebbe alcuna modifica alle definizioni POD. – Casey

1

Non posso dire con certezza cosa ci fosse nella mente del comitato quando hanno aggiunto questa restrizione alla definizione di aggregati. Ho il sospetto che sia perché hanno considerato che richiedere al compilatore di impostare un'istanza per le chiamate di funzioni virtuali (vtable o altro) sarebbe sufficientemente diversa dalla semplice inizializzazione dei valori e quindi aggiunto la restrizione per semplificare i requisiti sugli implementatori di linguaggio.

Problemi correlati