PDA

View Full Version : Extending QIODevice, is it possible?



davidovv
5th January 2014, 22:57
I have a need to add functionality (signals, slots, properties) to QIODevice, so that every class that inherits QIODevice (QFIle QSerialPort, QUDPSocket...) has this new members.
I overheard some colleagues talking about that functionality in c# (maybe i misunderstood)
Is it possible to do it in Qt (without recompiling or even modifying qt source)?
I tried with multiple inheritance (doesn't work if there are more QObject), interfaces (same thing, no signals and slots)...

ChrisW67
5th January 2014, 23:20
I have a need to add functionality (signals, slots, properties) to QIODevice, so that every class that inherits QIODevice (QFIle QSerialPort, QUDPSocket...) has this new members.
Why? What is problem you are trying to solve?

wysota
6th January 2014, 00:01
I have a need to add functionality (signals, slots, properties) to QIODevice, so that every class that inherits QIODevice (QFIle QSerialPort, QUDPSocket...) has this new members.
I overheard some colleagues talking about that functionality in c# (maybe i misunderstood)
Is it possible to do it in Qt (without recompiling or even modifying qt source)?
I tried with multiple inheritance (doesn't work if there are more QObject), interfaces (same thing, no signals and slots)...

I would also like to know what problems you are trying to solve this way but regardless, I can say that inheritance is not the only option to add new functionality to a class. There is a number of design patterns you can use here, including a decorator or just use composition.

davidovv
6th January 2014, 01:21
It is not really a problem, i have working solution but i would like to simplify it.
QIODevice has signal
readyRead()
signal, I would like to have signal
received(QByteArray)
because i have multiple receivers

I load all objects and connections dynamically, from database, and to create object i need to register it, and it needs to have constructor Q_INVOKABLE, so i created SerialPort (extending QSerialPort), UDPSocket (extending QUDPSocket)... with Q_INVOKABLE, slot receive() that connects on readyRead(), do readAll() data and emit received(QByteArray)
The code that extends readyRead() to received(QByteArray) is the same in all classes, so i want to have it in one place, written only once, like my IODevice.

composition: i could have SerialPort extend my IODevice and have a QSerialPort as member of SerialPort, but then i have difficulty configuring object and its connections (loaded from database) It is complicated to explain, but i end up with wrappers (again feels like writing duplicate code), or i have to give up database consistency, and i dont like doing that either.
decorator: It didn't cross my mind, and still have no idea how to apply decorator pattern with this situation, i will look more...

It all seamed like 'easy' if i could extend the base class with "non invasive" way. But i guess this is not possible (yet)

ChrisW67
6th January 2014, 04:31
I'm not sure where your Q_INVOKABLE requirements comes from. Why wouldn't a simple factory method cover constructing objects of two types base on data from your database? If you need something to handle an arbitrary list of types then perhaps look at qRegisterMetaType() and the QMetaType class. The QMetaType::construct() and QMetaType::type() will (I think) be of interest for constructing your objects from a type name string (which I what I think you are getting at).

Your receiver object will have to connect your new received() signal to a slot, so that slot must already exist. I would not have thought the one line needed to make the existing slot into a readyRead() handler slot is enough of a load to consider "simplifying." Maybe I am missing something.

davidovv
6th January 2014, 10:06
i tried with qRegisterMetaType(), long time ago, i dont remember for sure but i think that i gave up because of some copy constructor problems.
in current solution i keep a list of QMetaObject-s that i fill with &MyClass::staticMetaObject-s and when i want to create new object search for QMetaObject in that list and call newInstance(), that has Q_INVOKABLE constructor as requirement. (Q_INVOKABLE seamed cleaner solution than copy constructor)
QObject *myObject = static_cast<QObject*>(myMetaObject->newInstance());
And this works fine, like a factory, and i have a "lego" application that can be what i write in database.
It is not just about received() signal, that was just example. I have more common functionalities for my classes so it isn't just one line. It would be like a cherry on a cake if i could "inject" these functionalities in QIODevice, some even in QObject.

anda_skoa
6th January 2014, 10:58
The received(QByteArray) problem sounds a lot like having an abstract "connection", a data transport over some low level protocol.

In which case the most natural design IMHO is to model that into classes and keep the QIODevice hidden/encapsulated.

Something like


class Connection : public QObject
{
public:
explicit Connection(QIODevice *device, QObject *parent = 0);

Q_SIGNALS:
void received(const QByteArray &data);

public Q_SLOTS:
void send(const QByteArray &data);

private Q_SLOTS:
void onReadyRead();

private:
QIODevice *m_device;
};

Or even have different sub types depending on QIODevice type, potentially letting the subclass create the correct QIODevice, etc.

Cheers,
_