Thanks, that is also helpful.
What I'm trying to accomplish is essentially founded in Graph Theory.
In Qt, a connection 'just is'. It's made, and its lifetime is connected to the endpoints, but that's it.
However, if you consider the idea that a connection itself can be an object, like the relationship between a sender and receiver has a type and intention, and a sender and receiver can be connected many times with different roles, it becomes interesting. Within Qt, it may be that a signal and slot are being connected repeatedly, but the desire is that each of those connections are meaningful and unique. One could create lots of different signals and lots of slots to do this, but another way is to embed the intention as part of the signal itself, which would be a case for having a basic thing like:
{
Q_OBJECT
public:
sender();
signals:
trigger(roleType role, QVariantMap data);
};
{
Q_OBJECT
public:
recevier();
slots:
triggered(roleType role, QVariantMap data);
};
...
//somewhere else
connect(_sender, SIGNAL(trigger(roleType,QVariantMap)), _receiver, SLOT(triggered(roleType,QVariantMap)));
class sender : public QObject
{
Q_OBJECT
public:
sender();
signals:
trigger(roleType role, QVariantMap data);
};
class receiver : public QObject
{
Q_OBJECT
public:
recevier();
slots:
triggered(roleType role, QVariantMap data);
};
...
//somewhere else
connect(_sender, SIGNAL(trigger(roleType,QVariantMap)), _receiver, SLOT(triggered(roleType,QVariantMap)));
To copy to clipboard, switch view to plain text mode
But the sender may not know what its role is when emit()ing, and the connection wants to be smarter than that, so there wants to be an object layer and a connection layer that both offer intelligence to the system.
My thinking was that if connections are attached to the creator, then the lifetime of the connection object would take care of any cleanup. But instead it seems that the connection object wants to broker messages between endpoints and inject intelligence (filtering, queueing, routing, etc) that way. Which conceptually is simple enough but in Qt it ends up being a connect() from the sender to the connection, and then the connection to the receiver. It becomes a proxy link.
So now that I know that a connection object must maintain and proxy the connections (ie, Qt Signals/Slots aren't quite right all alone between objects for this purpose), I have to make connection objects that share qt signal/slot signatures (for API convenience), but internally the intelligence is in the connection object's polymorphism.
It becomes difficult when you have varieties of nodes that are descendants of a common base class who want to be agnostic to signals/slots, and the total set of connection roles are not known, but want to be able to be connected arbitrarily.
I'm trying to make something like Qt's signals/slots but with an extra bit in there that is not merely a connection, but a filtering/queueing/routing mechanism between threads and networked machines. It's a different layer of linkage, so parent/child associations are helpful during destructors, but a connection's lifetime may not be directly connected to the endpoints' lifetime.
So maybe this is better:
{
Q_OBJECT
public:
virtual ~base() {}
};
class sender : public base
{
Q_OBJECT
public:
sender
(QObject *parent
=0) : base
(parent
) {} virtual ~sender() {}
signals:
trigger(QVariantMap data);
};
class receiver : public base
{
Q_OBJECT
public:
recevier
(QObject *parent
=0) : base
(parent
) {} virtual ~receiver() {}
slots:
triggered(QVariantMap data);
};
{
Q_OBJECT
public:
connection
(base
*sender, base
*receiver
) : QObject(sender
) {
connect(sender, SIGNAL(trigger(QVariantMap)), this, SLOT(incoming(QVariantMap)));
connect(this, SIGNAL(outgoing(QVariantMap)), receiver, SLOT(triggered(QVariantMap)));
connect(sender, SIGNAL(destroyed()), this, SLOT(deleteLater()));
connect(receiver, SIGNAL(destroyed()), this, SLOT(deleteLater()));
}
virtual ~connection()
{
//connections will be destroyed automatically here
}
signals:
void outgoing(QVariantMap data);
slots:
virtual void incoming(QVariantMap data)
{
//something interesting here which may or may not emit a signal, or be overridden by a subclass
if (interesting)
emit outgoing(data);
}
};
//other code...
//somewhere else
sender *_sender = new sender(this);
receiver *_receiver = new receiver(this);
connection *c = new connection(_sender, _receiver);
class base : public QObject
{
Q_OBJECT
public:
base(QObject *parent=0) : QObject(parent) {}
virtual ~base() {}
};
class sender : public base
{
Q_OBJECT
public:
sender(QObject *parent=0) : base(parent) {}
virtual ~sender() {}
signals:
trigger(QVariantMap data);
};
class receiver : public base
{
Q_OBJECT
public:
recevier(QObject *parent=0) : base(parent) {}
virtual ~receiver() {}
slots:
triggered(QVariantMap data);
};
class connection : public QObject
{
Q_OBJECT
public:
connection(base *sender, base *receiver) : QObject(sender)
{
connect(sender, SIGNAL(trigger(QVariantMap)), this, SLOT(incoming(QVariantMap)));
connect(this, SIGNAL(outgoing(QVariantMap)), receiver, SLOT(triggered(QVariantMap)));
connect(sender, SIGNAL(destroyed()), this, SLOT(deleteLater()));
connect(receiver, SIGNAL(destroyed()), this, SLOT(deleteLater()));
}
virtual ~connection()
{
//connections will be destroyed automatically here
}
signals:
void outgoing(QVariantMap data);
slots:
virtual void incoming(QVariantMap data)
{
//something interesting here which may or may not emit a signal, or be overridden by a subclass
if (interesting)
emit outgoing(data);
}
};
//other code...
//somewhere else
sender *_sender = new sender(this);
receiver *_receiver = new receiver(this);
connection *c = new connection(_sender, _receiver);
To copy to clipboard, switch view to plain text mode
Sorry to ramble, but upon asking the question the structure becomes more clear, and those that have answered point out simple reductions that Qt's awesome engineering provide. It's surprisingly easy to overlook simple conveniences when swimming through complication!
thanks again!
Bookmarks