2015-04-15 2 views
13

У меня есть иерархия классов, которая сводится кVirtual Наследования с Конструктора Наследованием

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; }; 

Как вы можете видеть, я бы предпочел, чтобы создать некоторую базовую функциональность, и наследовать его в классическом ромбе. Я также хотел бы использовать наследование конструктора, чтобы сделать его на будущее, как это возможно ...

Однако 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); 

Даже замену определения InOutPort с более явной версией is not enough:

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

Вместо 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) { } }; 

Есть ли способ объединить наследование constuctor с виртуальным наследованием, которое я пропускаю?
Если нет, то какой вариант вы бы использовали?
Возможно, конструкторы шаблонов Variadic, которые отлично пересылают свои аргументы во все базы?

+0

'InPort' и' OutPort' наследуют конструктор, который вызывает неразделенный конструктор по умолчанию для 'Port', потому что они оба не являются наиболее производными классами. Программа была бы плохо сформирована, если бы они были вызваны. Из-за этого gcc решает удалить соответствующие конструкторы в обоих классах. Clang не дает и не будет давать ошибок в конструкторах, даже если базы [явно инициализированы] (http://coliru.stacked-crooked.com/a/7c2963ba56e79793). Как и в стороне, clang также дает ошибку, потому что 'Port' не является прямым базовым классом' InOutPort' в объявлении использования, в то время как gcc игнорирует его. – 0x499602D2

+0

GCC фактически удаляет конструкторы, потому что они будут плохо сформированы, но не по той причине, о которой я раньше догадывался. Кажется, что использование-декларация [неявно odr-использует конструктор по умолчанию] (http://coliru.stacked-crooked.com/a/490c0b5bb17fdc50). Конструктор по умолчанию в вашем классе 'Port' не объявлен, поэтому он удаляет вызывающий конструктор. Это ошибка. – 0x499602D2

+0

Кроме того, это происходит только в том случае, если это виртуальный базовый класс. – 0x499602D2

ответ

1

Не кажется, что существует какой-либо способ сделать такую ​​вещь. В 12,9/8:

... Для неявно определенного наследуя конструктор выполняет множество инициализаций класса, которые будут выполняться с помощью написанного пользователя встроенного конструктора для этого класса с мем-initializer- список которых только ают-инициализатор имеет MEM-инициализатор-идентификатор, который называет базовый классом обозначенный в вложенном имени спецификатора в использовании декларирования и выражений-список, как указано ниже ...

Другими словами, класс, конструктор которого вы наследуете, это только базовый класс, которому присваиваются аргументы. Все остальные базовые классы должны иметь конструкторы по умолчанию. Поскольку вы скрывали эти конструкторы по умолчанию в промежуточных классах, наследуя родительский конструктор, вы не можете вызывать их, как только вы явно наследуете родительский конструктор.

Я думаю, что вы должны иметь возможность использовать унаследованные конструкторы для обоих промежуточных классов и писать только явную версию для самого производного класса [я не видел, что вы уже пробовали это - это похоже на ошибку компилятора из моего понимание стандарта]. Я обновлю, если подумаю о другом лучшем подходе.

+0

Это в значительной степени то, что я понял после того, как вернул мой мозг обратно в курс виртуального наследования - но почему не работает средняя версия (явный «InOutPort» с наследованием «InPort» и «OutPort»)? Кажется, это ошибка g ++, не так ли? –

Смежные вопросы