reinterpret_cast для сублинга QObject

У меня есть какая-то фабрика объектов (на основе шаблонов), которая довольно хорошо работает для моих целей. Но теперь я попытался поработать с классом, который является производным от QObject и чистого абстрактного класса (интерфейса), и у меня возникли странные ошибки во время выполнения.

Вот простая картина этого класса (Производная)

class Interface  {
public:
Interface(){}
virtual ~Interface(){}
virtual int getResult() = 0;
};

class Derived : public QObject, public Interface {
Q_OBJECT
public:
explicit Derived(QObject *parent = 0);
int getResult();
};

и его реализация в производном.cpp:

#include "derived.h"Derived::Derived(QObject *parent)
: QObject(parent) {
}
int Derived::getResult() {
return 55;
}

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

#include "derived.h"void * create() {
return new Derived();
}

int main(int argc, char *argv[]) {
Interface * interface = reinterpret_cast<Interface *>(create());
int res = interface->getResult(); // Run-time error, or other method is called here
return 0;
}

Не могли бы вы объяснить, почему я не могу привести пустой указатель на интерфейс? И есть ли обходной путь?

Спасибо за ваши ответы

2

Решение

Переинтерпретация указателя на производный класс как указателя на базовый класс дает неопределенное поведение. Это подчеркивается множественным наследованием: поскольку существует более одного базового класса, а два базовых подобъекта должны иметь разные адреса, они не могут и то и другое иметь тот же адрес, что и производный объект. Таким образом, указатель возвращается вашим create функция указывает на Derived, но не обязательно Interface субобъект. Это может указывать на QObject подобъект или ни к одному.

Лучший вариант — вернуться Derived* или же Interface* от вашей функции; если это должно быть void* по какой-то причине, тогда единственный четко определенный состав, который вы можете сделать, это вернуться к Derived*, который затем может быть преобразован в Interface* используя стандартные преобразования.

Используя void* вы выбросили все статические и динамические знания о типе; единственный способ восстановить эту информацию — вернуть ее к правильному типу.

3

Другие решения

смешивание reinterpret_cast с множественным наследованием, вероятно, вызовет всевозможные проблемы. В вашем случае void* вероятно, будет указывать на QObject часть Derived, не Interface часть.

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

1

Обратите внимание, что в целом необходимость в этих типах приведений является признаком плохого дизайна. В вашем конкретном случае ваша заводская функция должна возвращать Interface*, void* в C ++, где нет взаимодействия с C, это просто ненужно и плохо.

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

Если это не сработает, вы захотите dynamic_cast. В Qt для QObjects вы можете увидеть, qobject_cast имеет какие-либо достоинства в вашей ситуации.

0
По вопросам рекламы [email protected]