Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. [Solved] Basic QIODevice subclass in Qt4
QtWS25 Last Chance

[Solved] Basic QIODevice subclass in Qt4

Scheduled Pinned Locked Moved C++ Gurus
49 Posts 4 Posters 31.1k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    paucoma
    wrote on last edited by
    #9

    [quote]
    how do you get a protected error for a public function?
    read and write are public methods.
    [/quote]

    Gerolf: ooops, I read that code too quickly... comes from looking at the same (similar) code too many times. Sorry, you are right. That solution I will have to look into... That was actually in the previous post too.. sorry for not paying attention.. Since in the Documentation it says only readData and writeData need to be reimplemented I had that idea quite fixed in my head and wasn't thinking about the other functions.

    bq. The problem is, I think, that you seem to want your class to work with any QIODevice as a “parent”, as as to chain them. Did I get that correctly?

    Correct!, I should have expressed that desire earlier.. I thought that too much information at once would confuse. but yes, I would like it to work on multiple classes which derive from QIODevice such as QBuffer and QFile.

    I will have a read, thanks.

    Thanks both very much for the quick and helpful responses!

    Ultimately I will probably inherit QFile for the moment and use base class calls, untill the challenge to extend to other IODevices comes.

    1 Reply Last reply
    0
    • G Offline
      G Offline
      giesbert
      wrote on last edited by
      #10

      If you read the docs for IODevices, it states you must implement readData and writeData, that' scorrect. but it didnÄ't say you have to call them! the logic is up to youm, and if you sue another device, use it's public interface.

      Nokia Certified Qt Specialist.
      Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

      1 Reply Last reply
      0
      • G Offline
        G Offline
        giesbert
        wrote on last edited by
        #11

        Hi,

        I created a wiki page as porting of the QQ 12 article to Qt 4:

        "wiki":http://developer.qt.nokia.com/wiki/CustomIoDevice

        the main code is:

        @
        qint64 CryptDevice::readData(char* data, qint64 maxSize)
        {
        qint64 deviceRead = underlyingDevice->read(data, maxSize);
        if (deviceRead == -1)
        return -1;
        for (qint64 i = 0; i < deviceRead; ++i)
        data[i] = data[i] ^ 0x5E;

        return deviceRead;
        

        }

        qint64 CryptDevice::writeData(const char* data, qint64 maxSize)
        {
        QByteArray buffer((int)maxSize, 0);
        for (int i = 0; i < (int)maxSize; ++i)
        buffer[i] = data[i] ^ 0x5E;
        return underlyingDevice->write(buffer.data(), maxSize);
        }
        @

        Nokia Certified Qt Specialist.
        Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

        1 Reply Last reply
        0
        • P Offline
          P Offline
          paucoma
          wrote on last edited by
          #12

          Thanks Gerolf, Great iniciative in porting the code!

          So if I understand correctly,

          -- readData() and writeData(...) are not part of the general class Interface and therefore I can be pretty sure that "normally" it won't be called on its own, but only indirectly through read().

          -- If I subclass QIODevice I should keep protected the reimplementations of readData(...) and writeData(...) to ensure this.

          1 Reply Last reply
          0
          • G Offline
            G Offline
            giesbert
            wrote on last edited by
            #13

            you are right, yes

            Nokia Certified Qt Specialist.
            Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

            1 Reply Last reply
            0
            • G Offline
              G Offline
              giesbert
              wrote on last edited by
              #14

              Hi,

              due to some bug, I updated the Wiki page.
              The constructor of the io device was lacking a QObject* parent object pointer. The example had a mistake, as the encrypted data should never be interpreted as string...

              it is now shown as hex code.

              Nokia Certified Qt Specialist.
              Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

              1 Reply Last reply
              0
              • P Offline
                P Offline
                paucoma
                wrote on last edited by
                #15

                Yea, the bad habit, or lets call it lazyness, of interpreting Bytes as string is just the quickest way to output "insignificant" data when you want to see that something is there or something is changing.

                On the other hand looking at the class declaration:
                @
                class CryptDevice : public QIODevice
                {
                public:
                explicit CryptDevice(QIODevice* deviceToUse, QObject* parent);
                ...
                @

                is this necessary because you have no other constructor that accepts a QObject ?

                could it be broken down to
                @
                class CryptDevice : public QIODevice
                {
                public:
                CryptDevice(QObject* parent);
                explicit CryptDevice(QIODevice* deviceToUse);
                ...
                @

                @
                CryptDevice::CryptDevice(QIODevice* deviceToUse) :
                underlyingDevice(deviceToUse)
                {
                }
                CryptDevice::CryptDevice(QObject* parent) :
                QIODevice(parent)
                {
                }
                @

                On a side note: What about the Q_OBJECT macro? I understand that this needs to be included when you want to use signals and slots mechanism.

                Thanks for the update.

                1 Reply Last reply
                0
                • G Offline
                  G Offline
                  giesbert
                  wrote on last edited by
                  #16

                  Hi Paucoma,

                  Q_OBJECT macro is needed, if this class uses signal slot, but my implementation has not signal/slot, no properties. So only the base classes have signal/slot and those have the macros, that's fine. But I add it, for completeness.

                  I removed the explicit for the constructor, and set the parent to 0. Two constructors makes no sense, as this device always needs an underlying device. The class en/decrypts data and stores it in the underlying device. Sure you can argue, otherwise you can open/close the device, change the underlying device by a method and open again, yes, but it's a code snippet, a description on how to implement a custom IO device.

                  Nokia Certified Qt Specialist.
                  Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    andre
                    wrote on last edited by
                    #17

                    Note that the Q_OBJECT macro has more uses than just signal/slot. It also is needed for introspection and things like qobject_cast<>(). That may or may not be nessecairy, but I think it is good practice to include Q_OBJECT by default for QObject derived classes.

                    1 Reply Last reply
                    0
                    • P Offline
                      P Offline
                      paucoma
                      wrote on last edited by
                      #18

                      Hi Gerolf!

                      Even though the custom IODevice, CryptDevice, does not implement signals and slots itself, it is a class derived from QIODevice which does provide signals, such as:

                      • void aboutToClose ()
                      • void bytesWritten ( qint64 bytes )
                      • void readChannelFinished ()
                      • void readyRead ()

                      To be able to use these signals from a CryptDevice Object is Q_OBJECT necessary in the definition of CryptDevice? or since QIODevice already declares it, it is not needed.

                      Your right, it doesn't make much sense to provide a seperate constructor.

                      I have been reading a bit on the explicit keyword and believe I understand that:

                      removing the explicit would now allow you to do
                      @
                      QBuffer bufferUsedLikeAFile(&dataArray);
                      SimpleCryptDevice deviceFilter = &bufferUsedLikeAFile;
                      @
                      before, with the explicit keyword, it would have thrown a compile error.

                      1 Reply Last reply
                      0
                      • A Offline
                        A Offline
                        andre
                        wrote on last edited by
                        #19

                        [quote author="paucoma" date="1300957763"]Even though the custom IODevice, CryptDevice, does not implement signals and slots itself, it is a class derived from QIODevice which does provide signals, such as:

                        • void aboutToClose ()
                        • void bytesWritten ( qint64 bytes )
                        • void readChannelFinished ()
                        • void readyRead ()

                        To be able to use these signals from a CryptDevice Object is Q_OBJECT necessary in the definition of CryptDevice? or since QIODevice already declares it, it is not needed.
                        [/quote]

                        It is not needed for signals and slots provided by a base class. There are, however, other reasons why you might want to include Q_OBJECT.

                        1 Reply Last reply
                        0
                        • P Offline
                          P Offline
                          paucoma
                          wrote on last edited by
                          #20

                          Thanks Andre for the clarification.

                          1 Reply Last reply
                          0
                          • G Offline
                            G Offline
                            giesbert
                            wrote on last edited by
                            #21

                            bq. To be able to use these signals from a CryptDevice Object is Q_OBJECT necessary in the definition of CryptDevice? or since QIODevice already declares it, it is not needed.

                            You can use signals and slots from base classes without the Q_OBJECT macro in CryptDevice. But as Andre mentions, there is more (like qobject_cast) that also relies on the meta object system. so now it is added.

                            @
                            QBuffer bufferUsedLikeAFile(&dataArray);
                            SimpleCryptDevice deviceFilter = &bufferUsedLikeAFile;
                            @

                            This should not be possible, as QObject assignement is a bad idea. So I also added QBuffer Q_DISABLE_COPY(CryptDevice) to the class. Now, no assignment or copy constructor is possible.

                            Explicit means it can't be used indirectly for conversion. So I reach the same by using Q_DISABLE_COPY. Explicit makes sense only for one parameter constructors, and the c'tor was changed to two parameters, so it made no sense anymore.

                            Nokia Certified Qt Specialist.
                            Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                            1 Reply Last reply
                            0
                            • P Offline
                              P Offline
                              paucoma
                              wrote on last edited by
                              #22

                              Quote from one of the articles I read about the explicit keyword:

                              "Explicit Constructor in C++ By Mridula":http://www.go4expert.com/forums/showthread.php?t=20756

                              bq. But explicit on a constructor with multiple arguments has no effect, since such constructors cannot take part in implicit conversions. However, explicit will have an effect if a constructor has multiple arguments and all but one of the arguments has a default value.

                              Which would be the case since the QObject defaults to 0, right?

                              1 Reply Last reply
                              0
                              • G Offline
                                G Offline
                                giesbert
                                wrote on last edited by
                                #23

                                But it had 2 parameters without default:

                                @
                                explicit CryptDevice(QIODevice* deviceToUse, QObject* parent);
                                @

                                Nokia Certified Qt Specialist.
                                Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                                1 Reply Last reply
                                0
                                • A Offline
                                  A Offline
                                  andre
                                  wrote on last edited by
                                  #24

                                  Normally in Qt, the parent parameter actually defaults 0. Perhaps that should be the case here too:

                                  @
                                  CryptDevice(QIODevice* deviceToUse, QObject* parent = 0);
                                  @

                                  However, even then, I think explicit is not needed. What would potentially be cast to QIODevice* that would not be a valid argument?

                                  1 Reply Last reply
                                  0
                                  • G Offline
                                    G Offline
                                    giesbert
                                    wrote on last edited by
                                    #25

                                    That's the difference in time :-)

                                    it already is, but the explicit was before the code of the c'tor was changed, and there the C'tor did not default it (in fact between I had 2 c'tors, that's why it couldn't default).

                                    Now we only have one c'tor which has a parent by default 0.

                                    code from above:

                                    @
                                    QBuffer bufferUsedLikeAFile(&dataArray);
                                    SimpleCryptDevice deviceFilter = &bufferUsedLikeAFile;
                                    @

                                    This code could result in a copy constructor / assignment operator call, depending on the compiler. It might be optimized. Both is not allowed for QObjects.

                                    Nokia Certified Qt Specialist.
                                    Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                                    1 Reply Last reply
                                    0
                                    • P Offline
                                      P Offline
                                      paucoma
                                      wrote on last edited by
                                      #26

                                      Lets see if I understand then:
                                      if we were to define the constructor as explicit:
                                      @
                                      explicit CryptDevice(QIODevice* deviceToUse, QObject* parent=0);
                                      @
                                      @
                                      QIODevice dev;
                                      QIODevice pdev;
                                      CryptDevice cdev_1(&dev); //call to explicit constructor
                                      CryptDevice cdev_2(pdev); //call to explicit constructor
                                      CryptDevice cdev_3(dev); //illegal! -> compiler error (expecting QIODevice
                                      )
                                      CryptDevice cdev_4(cdev_1); //call to compiler generated copy constructor
                                      CryptDevice cdev_5 = cdev_1; //call to compiler generated copy constructor
                                      CryptDevice cdev_6 = &dev; //illegal -> compiler error (expecting CryptDevice)
                                      @

                                      [quote] Q_DISABLE_COPY(CryptDevice) to the class. Now, no assignment or copy constructor is possible.[/quote]

                                      @
                                      Q_DISABLE_COPY(CryptDevice)
                                      CryptDevice(QIODevice* deviceToUse, QObject* parent=0);
                                      @
                                      @
                                      QIODevice dev;
                                      QIODevice *pdev;
                                      CryptDevice cdev_1(&dev); //call to constructor
                                      CryptDevice cdev_2(pdev); //call to constructor
                                      CryptDevice cdev_3(dev); // will it try type conversion?
                                      CryptDevice cdev_4(cdev_1); //illegal -> Copy disabled
                                      CryptDevice cdev_5 = cdev_1; //illegal -> operator= disabled
                                      CryptDevice cdev_6 = &dev; //illegal -> operator= disabled
                                      @

                                      Or have I just gotten completly lost...

                                      1 Reply Last reply
                                      0
                                      • G Offline
                                        G Offline
                                        giesbert
                                        wrote on last edited by
                                        #27

                                        Hi Pau,

                                        I copied your entry and fixed the comments:

                                        if we were to define the constructor as explicit:
                                        @
                                        explicit CryptDevice(QIODevice* deviceToUse, QObject* parent=0);
                                        @
                                        @
                                        QIODevice dev;
                                        QIODevice *pdev;

                                        CryptDevice cdev_1(&dev); //call to explicit constructor
                                        CryptDevice cdev_2(pdev); //call to explicit constructor
                                        CryptDevice cdev_3(dev); //illegal! -> compiler error (expecting QIODevice*)
                                        CryptDevice cdev_4(cdev_1); //call to compiler generated copy constructor --> will not work, as QIODevice has Q_DISABLE_COPY
                                        CryptDevice cdev_5 = cdev_1; //call to compiler generated copy constructor --> will not work, as QIODevice has Q_DISABLE_COPY
                                        CryptDevice cdev_6 = &dev; //illegal -> compiler error (expecting CryptDevice)
                                        @

                                        [quote] Q_DISABLE_COPY(CryptDevice) to the class. Now, no assignment or copy constructor is possible.[/quote]

                                        @
                                        Q_DISABLE_COPY(CryptDevice)
                                        CryptDevice(QIODevice* deviceToUse, QObject* parent=0);
                                        @
                                        @
                                        QIODevice dev;
                                        QIODevice pdev;
                                        CryptDevice cdev_1(&dev); //call to constructor
                                        CryptDevice cdev_2(pdev); //call to constructor
                                        CryptDevice cdev_3(dev); // illegal! -> compiler error (expecting QIODevice
                                        )
                                        CryptDevice cdev_4(cdev_1); //illegal -> Copy disabled
                                        CryptDevice cdev_5 = cdev_1; //illegal -> operator= disabled
                                        CryptDevice cdev_6 = &dev; //illegal -> operator= disabled
                                        @

                                        Or have I just gotten completly lost...

                                        Nokia Certified Qt Specialist.
                                        Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                                        1 Reply Last reply
                                        0
                                        • P Offline
                                          P Offline
                                          paucoma
                                          wrote on last edited by
                                          #28

                                          Hi Gerolf: thanks for fixing the comments.
                                          In the first section I am suposing we dont declare the macro Q_DISABLE_COPY(CryptDevice)

                                          • In that case, will the compiler automatically generate a copy constructor?
                                            ** If so, are the following legal?
                                            *** CryptDevice cdev_4(cdev_1);
                                            *** CryptDevice cdev_5 = cdev_1;
                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved