2014-11-05 5 views
1

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

Вот код, который не компилируется:

struct BottomClass 
{ 
    BottomClass(int& ref) : ref(ref) {} 
    int& ref; 
}; 

struct MiddleClassA : virtual public BottomClass 
{ 
    MiddleClassA() /*: BottomClass()*/ {} 
    virtual ~MiddleClassA() = 0; 
}; 

MiddleClassA::~MiddleClassA(){} 

struct MiddleClassB : virtual public BottomClass 
{ 
    MiddleClassB() /*: BottomClass()*/ {} 
    virtual ~MiddleClassB() = 0; 
}; 

MiddleClassB::~MiddleClassB(){} 

struct TopClass final : public MiddleClassA, public MiddleClassB 
{ 
    TopClass(int& ref) : BottomClass(ref) {} 
}; 

void main() 
{ 
    int someInt; 
    TopClass variable(someInt); 
} 

Что беспокоит меня, почему это не компилируется. Я знаю, что для BottomClass нет конструктора по умолчанию, и поэтому MiddleClassX плохо сформирован. Но MiddleClassX - абстрактные классы! Даже если бы я указал конструктор там, он не будет использоваться ни при каких обстоятельствах ... так почему я должен его указывать?

Я не мог даже дать разумный конструктор, потому что MiddleClassX не имеет разумной ценности, чтобы дать BottomClass.

Мой вопрос: есть ли элегантное решение этой проблемы?


У меня есть несколько решений сам, но мне не нравится ни один из них особенно:

1) я мог бы создать конструктор по умолчанию BottomClass, который использует какое-то значение для мусора, чтобы построить свою реф. И затем assert() в этом конструкторе, поэтому я знаю, что он никогда не вызывается ... Конечно, это приводит к тому, что мне приходится выполнять проверку временем всего, что должно быть ошибкой времени компиляции, и это также практически требует существования целое число мусора, чтобы получить ссылку.

2) Я мог бы передать ссылку на каждый абстрактный средний класс и использовать это ... Но это приводит к серьезному повторению информации, и когда эти цепочки становятся длинными (как и они), очень утомительно поддерживать это. Существует также удар производительности, связанный с передачей дополнительной переменной каждому классу.

(прошу прощения, если мой вопрос трудно понять - если кто-то может лучше описать мою дилемму, что было бы удивительным, я бросил вызов, чтобы поместить это в слова)

ответ

1

Даже если я указал конструктор там он не будет использоваться ни при каких обстоятельствах

Неправильно. Конструкторы на абстрактных классах используются производными классами. Абстрактные классы по-прежнему требуют инициализации, единственное, что особенно касается абстрактных классов, состоит в том, что вы не можете напрямую их построить; только производным классам разрешено создавать их и только как часть их собственной конструкции.

Нельзя получить абстрактный класс без конструкторов, как и любой другой класс без конструкторов.

Ваше второе решение является правильным. Если конструкторы вверх по цепочке встраиваются, то нет никакого удара производительности вообще.

(Кстати, это не имеет ничего общего с виртуальным наследованием. Вы столкнетесь с той же проблемой, с не виртуальным наследованием.)

+0

Хорошо, что я имею в виду то есть: заменить конструкторы с MiddleClassX(): BottomClass (((станд :: соиЬ << "Распечатать меня"), somegarbageint)) {} сейчас , не существует ситуации, когда «Печать меня» будет напечатана без изменения первоначальных классов. – Ace24713

+0

Возможно, вы не помните различия между виртуальным наследованием и не виртуальным? Фактически унаследованный базовый класс требует * явной конструкции из класса EVERY по цепочке производных классов ... Моя проблема связана с этим, потому что мне нужно указывать конструктор в тех местах, где он будет вынужден переопределяться в любом случае. – Ace24713

+0

Извините, я почти уверен, что это относится только к виртуальному наследованию. Это просто, если вы думаете, что это не так, я, вероятно, неправильно отреагировал на свой вопрос ... – Ace24713

1

Почему бы не объявить конструктор по умолчанию ...

BottomClass(); // deliberately undefined; use Bottom(int&) 

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

Посмотреть на ideone.com

+0

Это не компилируется для меня (Visual Studio 2013). Было бы здорово, если бы это было! Но ... это меня удивляет, что он работает на ideone, на самом деле ... – Ace24713

+0

@ Ace24713 Могу попробовать префикс с 'template ' then ... должен быть создан только в том случае, если он действительно называется .... –

+0

Я действительно думал о что раньше, но не повезло. Он по-прежнему пытается связать его. Если есть какие-либо доказательства того, что этот код должен компилироваться по стандарту C++, я бы написал отчет об ошибке и покончил с этим? – Ace24713

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