Вообще говоря, интерфейсы должны быть абстрактными классами, а их конструкторы вообще ничего не должны делать. Так что это плохой дизайн.
Если вы настаиваете на том, чтобы делать такие вещи, семантика C++ мешает нам делать это точно так, как вы заявляете. Когда вы умножаете наследование, dynamic_cast
к C
не удастся, пока конструктор C
не вводится:
struct Interface {
Interface() { assert(dynamic_cast<QObject*>(this) == 0); }
};
struct C : public QObject, public Interface {
C() { assert(dynamic_cast<QObject*>(this)); }
};
Итак, нам нужно каким-то образом задерживая соединение до полного объекта был построен, или, по крайней мере до тех пор, QObject
его часть.
Простой способ будет для интерфейса явно требуется база будет построена:
struct Interface {
Interface(QObject * base) {
connect(base, ...);
}
};
struct C : public QObject, public Interface {
C() : Interface(this) {}
};
Конструктор подписи красиво выражает намерение: Interface
предназначается для использования на классах, вытекающих из QObject
. Это не будет работать на тех, кто этого не делает.
Другой способ заключается в том, чтобы задержать соединение до тех пор, пока цикл событий не сможет запустить. Это приемлемо, если соединение не требуется раньше, чем это. Это не требует, чтобы конструктор Interface
передавал явный указатель на базовый класс.
Таймер принадлежит диспетчеру событий для текущего потока, поэтому он не будет течь, даже если цикл событий не запускается.
class Interface {
public:
virtual void request() = 0; // entirely optional
Interface() {
auto timer = new QTimer(QAbstractEventDispatcher::instance());
timer.start(0);
QObject::connect(timer, &QTimer::timeout, [this, timer]{
timer.deleteLater();
connect(dynamic_cast<QObject*>(this), SIGNAL(request()), ...);
});
}
};
Обратите внимание, что во всех случаях совершенно бесполезно, чтобы сигнал был объявлен виртуальным в интерфейсе. Конструктор Interface
может проверить, присутствует ли сигнал, и утверждать его, или даже всегда abort()
.
Просто объявляя виртуальный сигнал, не гарантирует, что сигнал на самом деле является сигналом.Ниже не будет работать, даже если компилятор не обеспечивает диагностику наоборот:
struct Interface {
signals:
virtual void aSignal() = 0;
};
struct Implementation : public QObject, public Interface {
void aSignal() {} // not really a signal!
};
Это обнаружит отсутствующий сигнал на время выполнения:
struct Interface {
// No need for virtual signal!
Interface(QObject * base) {
Q_ASSERT(base->metaObject()->indexOfSignal("request()") != -1);
}
};
struct Implementation : public QObject, public Interface {
Q_OBJECT
Q_SIGNAL void reuest(); // a typo
Implementation() : Interface(this) {} // will assert!
};
лучший способ гарантировать, что виртуальный сигнал а затем может быть сделать оба, и объявить реализацию сигнала в качестве переопределения:
struct Interface {
virtual void aSignal() = 0;
Interface(QObject * base) {
Q_ASSERT(base->metaObject()->indexOfSignal("request()") != -1);
}
};
struct Implementation : public QObject, public Interface {
Q_OBJECT
Q_SIGNAL void request() Q_DECL_OVERRIDE;
Implementation() : Interface(this) {}
};
компилятор поймать опечаток , даже если вы никогда не создаете экземпляр Implementation
, и интерфейс проверяет во время выполнения, что сигнал реализации на самом деле является сигналом, а не каким-либо другим методом.
Следует также отметить, что раздел signals:
Interface
является фиктивным.
signals
препроцессора макрос с пустым расширением: компилятор, он ничего не делает.
Interface
не является QObject
и поэтому игнорируется moc.
signals:
имеет смысл только тогда и только тогда MOC это в классе, который как:
- производный от
QObject
и
- содержит
Q_OBJECT
макрос.
Вообще говоря, виртуальные сигналы имеют мало смысла. Все они «виртуальны» в том смысле, что вы можете подключать вещи, не предоставляя компилятору виртуальный метод.
Наконец, они не работают с Qt 5 во время компиляции проверяется синтаксис либо, так как Interface
не конкретный QObject
-deriving класс с соответствующим сигналом
Какую ошибку вы получаете? –
@MatthewRead Спасибо за вопрос. 'this' в' QObject :: connect' не является QObject. – SaMax
О, ну, 'AbsView' нужно будет расширить' QObject'. –