2015-04-15 12 views
13

Ho una gerarchia di classi, che si riduce aEredità virtuale con il costruttore Inheritance

class Module { }; 

struct Port { 
    Module& owner; 
    Port(Module& owner) : owner(owner) {} 
}; 

struct InPort : virtual Port { using Port::Port; }; 
struct OutPort : virtual Port { using Port::Port; }; 
struct InOutPort : InPort, OutPort { using Port::Port; }; 

Come potete vedere, io preferirei di creare alcune funzionalità di base, ed ereditare in un modello di diamante classico. Mi piacerebbe anche usare costruttore di ereditarietà per renderlo a prova di futuro possibile ...

Tuttavia, this does not work as written down above

prog.cpp: In function 'int main()': 
prog.cpp:14:15: error: use of deleted function 'InOutPort::InOutPort(Module&)' 
    InOutPort p(m); 

Anche la sostituzione della definizione di InOutPort con una versione più esplicita is not enough:

struct InOutPort : InPort, OutPort { InOutPort(Module& m) : Port(m), InPort(m), OutPort(m) { } }; 

Invece I seem to have to write down everything explicitly for it to work::

struct InPort : virtual Port { InPort(Module& m) : Port(m) { } }; 
struct OutPort : virtual Port { OutPort(Module& m) : Port(m) { } }; 
struct InOutPort : InPort, OutPort { InOutPort(Module& m) : Port(m), InPort(m), OutPort(m) { } }; 

C'è un modo per combinare l'ereditarietà del constuctor con l'ereditarietà virtuale che sto trascurando?
In caso negativo, quale alternativa useresti?
Forse costruttori di modelli variadici che inoltrano perfettamente i propri argomenti a tutte le basi?

+0

'InPort' e' OutPort' ereditano entrambi un costruttore che chiama il costruttore di default non dichiarato per 'Port' perché non sono entrambi una classe di derivazione più elevata. Il programma sarebbe mal formato se fossero stati chiamati. Per questo motivo, gcc decide di eliminare i costruttori corrispondenti in entrambe le classi. Clang non ha e non darà un errore sui costruttori anche quando le basi sono [inizializzate esplicitamente] (http://coliru.stacked-crooked.com/a/7c2963ba56e79793). Per inciso, clang dà anche un errore perché "Port" non è una classe di base diretta di "InOutPort" nella dichiarazione di utilizzo, mentre gcc lo ignora. – 0x499602D2

+0

GCC infatti elimina i costruttori perché sarebbero mal formati, ma non per il motivo che ho precedentemente ipotizzato. Sembra che la dichiarazione d'uso [implicitamente odr-usi il costruttore predefinito] (http://coliru.stacked-crooked.com/a/490c0b5bb17fdc50). Il costruttore predefinito nella tua classe 'Port' non è dichiarato, quindi elimina il costruttore chiamante. Questo è un bug – 0x499602D2

+0

Inoltre, accade solo se si tratta di una classe base virtuale. – 0x499602D2

risposta

1

Non sembra che ci sia un modo per fare una cosa del genere. Nel 12,9/8:

... Un costruttore ereditare implicitamente definito esegue la serie di inizializzazioni della classe che avrebbe essere eseguite da un costruttore linea scritto dall'utente per quella classe con un mem-initializer- lista il cui solo mem-inizializzatore ha una mem-inizializzatore-id che indica la classe base denotato nel nested-nome-specificatore della dichiarazione using e un'espressione lista come in appresso ...

In altre parole, la classe di cui si eredita il costruttore è la solo la classe base che riceve gli argomenti inoltrati. Tutte le altre classi base devono avere costruttori predefiniti. Poiché hai nascosto i costruttori predefiniti nelle classi intermedie ereditando il costruttore genitore, non puoi chiamarli dopo aver ereditato esplicitamente il costruttore genitore.

Penso che dovresti essere in grado di utilizzare i costruttori ereditati per entrambe le classi intermedie e solo scrivere la versione esplicita per la classe più derivata [Non ho visto che hai già provato questo: sembra un bug del compilatore dal mio comprensione dello standard]. Aggiornerò se penso ad un altro approccio migliore.

+0

Questo è più o meno quello che ho immaginato dopo aver attorcigliato il mio cervello nel corso dell'ereditarietà virtuale - ma perché la versione intermedia ("InOutPort" esplicita con l'ereditarietà di "InPort" e "OutPort") non funziona? Sembra un bug g ++, vero? –