Множествено наследяване на QObject поради достъпа до метода deleteLater().

Използвам наблюдаем модел в моята програма. Всичко работеше, преди да се наложи да променя малко кода. Ако трябва да бъда точен, промених наследяването на класа IObserver - в момента той наследява QObject:

class IObserver : public QObject
{
...

Направих го само поради едно нещо - имам нужда методът deleteLater() да се използва в наблюдател, за да мога да извикам имплементация на виртуална функция deinitialization() на IObserver. Така бих могъл да стандартизирам всеки манипулатор на съобщения IObserver.

Проблемът е, че вече наследих QObject (индиректно) в някои класове Observer. Като MainForm или AboutDialog. Всичко върви добре, докато не опитам да извикам метода „connect“ в класа AboutDialog.

Какво мога да направя? Наистина се нуждая от този метод deleteLater(), тъй като не мога да използвам „изтрий това“ в кода на IObserver - това ще извика деструктора на IObserver, а не класовете MainForm или Storage например.

Благодаря ти.


person Alex Tiger    schedule 11.12.2013    source източник
comment
може би някакъв намек тук: http://stackoverflow.com/questions/3259728/using-qt-signals-and-slots-with-multiple-inheritance   -  person epsilon    schedule 11.12.2013


Отговори (2)


Наистина се нуждая от този метод deleteLater(), тъй като не мога да използвам „изтрий това“ в кода на IObserver - това ще извика деструктора на IObserver, а не класовете MainForm или Storage например.

Ако направите своя деструктор виртуален (и трябва!), той ще извика извлечения деструктор съвсем добре. Но проблемът е, че унищожаването на обект, докато той обработва някакъв сигнал/слот, може да причини проблеми с цикъла на събитията. Така или иначе ще трябва да сте много внимателни с delete this.

Проблемът е, че вече наследих QObject (индиректно) в някои класове Observer.

Един от начините, по които можете да приложите това, не съм сигурен дали е най-добрата мисъл:

template <typename Derived>
class IObserver
{

    // Just to be sure: (C++11)
    static_assert(is_base_of<Derived, QObject>::value,
                  "must inherit from QObject when using IObserver");

    void deleteMe()
    {
        QObject* thisObject = dynamic_cast<QObject*>(this);
        // no need for check if thisObject equals null. static assert does this.
        thisObject->deleteLater();
    }

};

class MainForm : public IObserver<MainForm>, public QMainWindow
{
    // ...
};

Вярвам, че този модел се нарича статичен полиморфизъм.

person Guilherme Bernal    schedule 11.12.2013
comment
Ако направите своя деструктор виртуален (и трябва!) Използвам virtual void deinitialisation() = 0 в IObserver и вярвам, че във внедрената версия всички ресурси ще бъдат освободени, така че след извикване на deinit искам да изтрия обекта. Благодаря за примера, утре ще пробвам. - person Alex Tiger; 11.12.2013
comment
Проблемът е, че ако някой реши да delete anIObserverPointer няма да изчисти ресурсите на производния клас. Също така, защо не преместите кода от deinitialization() на ~IObserver()? Много по-безопасно. - person Guilherme Bernal; 11.12.2013

Изоставяне на наследяването на QObject за IObserver. Вместо това добавете такъв метод към интерфейса.

class IObserver : public QObject {
public:
   QObject *object() const = 0;
...

След това, ако изпълнението на интерфейса наследи QObject, ще върнете this указател от object() метод. Ако изпълнението на интерфейса не наследява QObject, можете просто да върнете указател към някакъв прост QObject, който ще се справи с унищожаването на този обект. След това можете просто да свържете deleteLater за обект, върнат от този метод.

Извън темата
Използването на интерфейси за наблюдение в Qt обикновено е остаряло, слотовете и сигналите вършат тази работа перфектно и това е по-гъвкав подход.

person Marek R    schedule 11.12.2013
comment
› работа перфектно Не във всеки случай. Когато има нужда всеки възможен сигнал да бъде записан в дневник, трябва да свърже този сигнал с функции за дневник, което не е стандартизирано. Вместо да правя 20-30 функции между тях, използвам обща функция с 3 параметъра (същата идея като SendMessage на windows). Освен това мога напълно да изтрия наблюдателите, без да повредя приложението. Вместо да извикам конкретна функция, например profileManager.getProfilesList, извиквам Send(OC_PROFILEMNGR, MC_GETPRFNAMES, &myStringList). Така че не ме интересува дали има някаква функция като getProfileList или дори дали такъв мениджър съществува. - person Alex Tiger; 11.12.2013