Signale und Slots

Wer schonmal mit QT gearbeitet hat, dem sind Signale und Slots natürlich ein Begriff. Neben den grundlegenden Dingen wie dem Q_OBJECT-Makro gibt es jedoch in einigen Fällen noch ein paar weitere Dinge zu beachten.

Vererbung

Bei normaler Vererbung gibt es kein Problem - einfach behandeln wie sonst auch. Aber es gibt Fälle, in denen man um Mehrfachvererbung nicht rumkommt. Klassisches Beispiel ist die Verwendung von Interfaces.

Man nehme ein einfaches Beispiel (welches natürlich auch anders gelöst werden könnte) - eine Resourcen-Pipeline. Man benötigt also:

Nun soll es möglich sein, eine Kette Quelle - Prozessor1 - … - ProzessorN - Senke zu erzeugen. Es bietet sich hierbei an, Signale „output“ und Slots „input“ zu definieren, dann kann die Kette einfach mit

connect(source,SIGNAL(output(..)),processor1,SLOT(input(..)));

usw. erzeugt werden. Soweit so gut. Allerdings wäre es ja auch schön, wenn man einfach nur

connect(source,processor1)

schreiben könnte. Genau genommen, ist ein Prozessor ja auch garnichts anderes als gleichzeitig Quelle und Senke.

Damit würde das oben genannte aber funktionieren, etwa so:

void connect(Source *a, Sink *b){
    connect(a,SIGNAL(output(...)),b,SLOT(input(...)));
}

Alles zusammengenommen wäre es also wünschenswert, ein Basisklasse oder noch genauer ein Interface Quelle zu haben, welche das Signal „output“ erzwingt und ein Interface, welche den Slot „input“ erzwingt.

Nun ist es aber so, dass man nicht mehrfach von QObject erben kann - ich habe deshalb keine Möglichkeit gefunden, oben gesetzte Ziele (also das erzwingen von Signals/Slots) vollständig zu erreichen. Was man aber machen kann ist folgendes:

class Source{
    protected:
        void output(...)=0;
};

class Sink
    protected:
        void input(...)=0;
};

Das funktioniert insofern, als die abgeleiteten Klassen zumindest output bzw. input implementieren *müssen*. Insbesondere kann output dabei als Signal deklariert werden:

class Processor:public QObject, public Sink, public Source{
    Q_OBJECT
    ...
    public slots:
        void input(...);
    public signals:
        void output(...);
};

void Processor::input(...){
    ...
    emit output(...);
}

Allerdings muss zudem die oben erstellte connect noch leicht geändert werden:

void connect(Source *a, Sink *b){
    connect(dynamic_cast<QObject*>a,SIGNAL(output(...)),dynamic_cast<QObject*>b,SLOT(input(...)));
}