2010-01-27 2 views
0

Я пытаюсь использовать форвардные декларации и d-указатели для устранения некоторых зависимостей include. Все работает хорошо, за исключением того, что во многих местах я использовал XList typedefs для чтения (например: typedef QList<X> XList).Наследование из контейнера с не виртуальным деструктором

Обходной путь для проблемы с объявлением опечатки typedef заключается в использовании наследования: class XList : public QList<X>{};. QList имеет не виртуальный деструктор. Учитывая тот факт, что Qt's QStringList наследует QList<QString>, и я не выделяю XLists в кучу, вы видите какие-либо проблемы с этим обходным решением? Должен ли я явно запрещать выделение кучи для классов XList?

+0

Интересно, насколько важно удалить ** все ** включить зависимости, особенно по сравнению с использованием небезопасных, унииоматических конструкций ... Иногда вам лучше стоять в средней земле: удалять как можно больше зависимостей, не впадая в мутную воды. –

+0

Вот что мне было интересно. Меня беспокоит его унииоматичность. Насколько я могу определить, это будет безопасно, особенно если я статически запрещаю выделение кучи, хотя я тоже хотел бы проверить его. – rpg

+0

В качестве альтернативы вы можете создать заголовочный файл «FooListDeclare.h», который в основном «#include \ nclass Foo; \ ntypedef QList FooList;". Я считаю, что это позволит вам объявить typdef, не требуя зависимости определения класса в любом месте, которое вам уже не понадобилось. –

ответ

1

Давайте посмотрим, что произойдет, если мы определим XList таким образом:

class XList : public QList<X> {}; 

Ниже будет работать, как ожидалось:

XList* x = new XList; 
    delete x; 

Однако следующий не будет:

QList<X>* q = new XList; 
    delete q; 

QList<X> деструктор будет называться, но не XList, если есть. Это то, что виртуальный деструктор в базовом классе сделает для вас.

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

Удостоверьтесь, что это допущение задокументировано и сделать XListnew оператором частного действия, чтобы предотвратить создание кучи, как вы упомянули.

Безопасная альтернатива будет делать QList<X> членом вашего XList, то есть: предпочесть инкапсуляцию в наследование.

+0

Я обнаружил, что, поскольку я использую XLists как метатипы QVariant, я не могу сделать 'new' private; хотя я не делаю никаких ассигнований, QVariant делает. Обходной путь должен по-прежнему работать, но он становится слишком хриплым для моих вкусов. – rpg

0

QStringList не определяет свой собственный деструктор. В этом случае, даже если QList был использован полиморфно (см. Пример blue.tuxedo), проблема не возникает, поскольку даже если деструктор производного класса не будет вызван, его не будет определено.

В вашем случае, если вам нужен деструктор в производном классе (XList), у вас возникнут проблемы. Была предыдущая дискуссия о том, как обойти не в состоянии направить объявляете определение типа здесь:

Forward declaration of a typedef in C++

Если вы можете избежать написаний производного класса, вы могли бы быть лучше в долгосрочной перспективе.

+0

Это рецепт катастрофы ... Просто потому, что в текущей реализации вашей системы неопределенное поведение не кусается, вы не делаете код правильным. –

+0

Согласовано - разработчики должны были бы не писать деструктор в производном классе. Кто-то, в конце концов, забудет, что просто вызовет трудные проблемы. В этом смысле вы можете утверждать, что Qt рискует с QStringList. –

+0

Хотя QStringList не определяет деструктор, он будет создан компилятором, так как базовый класс имеет деструктор. Трюк typedef также не будет работать, потому что я хочу, чтобы заголовок клиента не зависел ни от X, ни от QList. – rpg

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