views:

566

answers:

3

So I have starting to learn Qt 4.5 and found the Signal/Slot mechanism to be of help. However, now I find myself to be considering two types of architecture.

This is the one I would use

class IDataBlock
{
   public:
   virtual void updateBlock(std::string& someData) = 0;
}

class Updater
{

   private:
    void updateData(IDataBlock &someblock)
    {
         ....
       someblock.updateBlock(data);
          ....
    }
}

Note: code inlined for brevity.

Now with signals I could just

void Updater::updateData()
{
    ...
    emit updatedData(data);
}

This is cleaner, reduces the need of an interface, but should I do it just because I could? The first block of code requires more typing and more classes, but it shows a relationship. With the second block of code, everything is more "formless". Which one is more desirable, and if it is a case-by-case basis, what are the guidelines?

+3  A: 

There is another difference. #1 is hard coupled to the IDataBlock interface, and the Updater class needs to know about "someblock". #2 can be late-coupled via a connect call (or several, including disconnects), which leads to a more dynamic approach. #2 acts like a message (think Smalltalk/ObjC) and not a call (think C/C++). Messages can also be subject to multiple dispatch, which requires hand implementing that feature in #1.

My preference would be to utilize signals/slots due to their flexibility, unless code performance or the need for immediate return data does not allow for it (or the dependence on Qt is not desirable).

Yann Ramin
+3  A: 

Emmitting a signal costs few switches and some additional function calls (depending on what and how is connected), but overhead should be minimal.

Provider of a signal has no control over who its clients are and even if they all actually got the signal by the time emit returns.

This is very convenient and allows complete decoupling, but can also lead to problems when order of execution matters or when you want to return something.

Never pass in pointers to temporary data (unless you know exactly what you are doing and even then...). If you must, pass address of your member variable -- Qt provides a way to delay destruction of object untill after all events for it are processed.

Signals also might requre event loop to be running (unless connection is direct I think).

Overall they make a lot of sense in event driven applications (actually it quickly becomes very annoying without them).

If you already using Qt in a project, definitely use them. If dependency on Qt is unacceptable, boost has a similar mechanism.

Eugene
+1  A: 

The two forms may appear to be similar. Functionally, that is true. In practice, you are solving a larger problem. In those cases, external circumstances will cause these two soltuions to be not equivalent.

A common case is figuring out the relation between source and sink. Do they even know each other? In your first example, updateData() needs to have the sink passed in. But what if the trigger is a GUI button [Update Data] ? Pushbuttons are generic components and shouldn't know about IDataBlock.

A solution is of course to add a m_someblock member to Updater. The pushbutton would now update whatever member is in Updater. But is this really what you intended?

MSalters