Как правильно привести к типу в C++\Qt?

Есть вот такой незамысловатый header:
#define PQ_OBJECT \
public:\
    QStringList myList;

class PQWidget;
class PQWidget : public QWidget {
    Q_OBJECT
    PQ_OBJECT

public:
    Q_INVOKABLE explicit PQWidget(QWidget *parent = 0)
        : QWidget(parent){}
    virtual ~PQWidget(){}
};

class PQPushButton;
class PQPushButton : public QPushButton {
    Q_OBJECT
    PQ_OBJECT

public:
    Q_INVOKABLE explicit PQPushButton(QWidget *parent = 0)
        : QPushButton(parent) {
        myList << "text1";
        myList << "text2";
    }
};


и код:
// QObject -> PQWidget
    QObject *button = new PQPushButton;
    PQWidget *pbutton = (PQWidget*) button;

    if(pbutton->myList.contains("text1")) {
        qDebug() << "Okay!";
    }

    qDebug() << "QObject -> PQWidget OK!";

вроде написано всё честно и справедливо - PQWidget является потомком QWidget, как и кнопка - она тоже потомок QWidget , QWidget от QObject. И все они после моего наследования имеют поле myList. Код работает. И какой бы виджет я не писал с добавлением макроса PQ_OBJECT, будь то различные кнопки, текстовые поля, контейнеры и... короче, если взять абсолютно любой виджет, он прекрасно преобразуется в PQWidget и не выпендривается :)

А вот второй похожий случай:
class PQObject;
class PQObject : public QObject {
    Q_OBJECT
    PQ_OBJECT

public:
    Q_INVOKABLE explicit PQObject(QObject *parent = 0)
        : QObject(parent){}
    virtual ~PQObject(){}
};

class PQTimer;
class PQTimer : public QTimer {
    Q_OBJECT
    PQ_OBJECT

public:
    Q_INVOKABLE explicit PQTimer(QObject *parent = 0)
        : QTimer(parent) {
        myList << "text1";
        myList << "text2";
    }
};


// QObject -> PQObject
    QObject *timer = new PQTimer;
    PQObject *ptimer = (PQObject*) timer;

    if(ptimer->myList.contains("qwerty")) { // Segmentation fault
        qDebug() << "Okay!";
    }

    qDebug() << "QObject -> PQObject OK!";

Все написано в точности так же как и с QWidget. Полная аналогия: PQObject и QTimer - потомки QObject. PQObject и PQTimer имеют поля myList. На этапе преобразования QObject -> PQObject программа работает, но при попытке обратится к какому либо полю из PQ_OBJECT - сегфолт.

Ребята, прокомментируйте, пожалуйста, такое поведение? Почему в первом случае код работает, а во втором - нет? Должен ли он вообще был работать или это случайность, которая оказалась случайной для всех виджетов? :)

П.с. хочу заметить, что унаследоваться от PQObject , как по идее и должно было быть, я не могу, потому что Qt не допускает двойное наследование Q_OBJECT, а мой PQObject обязательно должен быть наследником QObject.

П.п.с. макрос обрезал для читаемости, на самом деле в нем намного больше полей и методов и все они доступны (проверено) при приведении к PQWidget.
  • Вопрос задан
  • 434 просмотра
Пригласить эксперта
Ответы на вопрос 2
PavelK
@PavelK
qmake не может правильно moc собрать скорее всего.
Попробуйте явное приведение
QObject * myObj = qobject_cast(PQTimer);
Ответ написан
Adamos
@Adamos
Вообще такое приведение - это наследие С, и в С++ - моветон.
Если же заменить его dynamic_cast и проверять результат на NULL, могут вскрыться всякие нюансы.
У меня, например, были проблемы с приведением родительского окна к тому классу, которым оно должно было быть. Исследование показало, что в версии библиотеки под одну из платформ дочерний класс заворачивался еше в одного родителя, и такое приведение вызывало сегфолт...
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы