Results 1 to 8 of 8

Thread: qobject_cast<T> in shared libraries...

  1. #1
    Join Date
    Dec 2008
    Posts
    29
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default qobject_cast<T> in shared libraries...

    Hi,
    I have a question for advanced users or Qt developers..
    As far as I can imagine, the qobject_cast provides a safe cast in the QObject* inheritance hierarchy where each node uses Q_OBJECT macro.
    Dynamic_cast does practicly the same, but needs RTTI. RTTI isn't always available (for example for objects shared cross two shared libraries in windows, sometimes also in linux as I realized after some tests (ABI)..)

    I want to have an interface implemented in one shared library that is used in another shared library... Each interface is managed by PluginManager (singleton object) as an QObject*. Lets have an example:

    class IObjekt2 : public QObject
    {
    Q_OBJECT
    protected:
    int m_id;
    public:
    IObjekt2( int id, QObject *parent = 0 ) : QObject(parent), m_id(id) {}
    virtual ~IObjekt2() {}
    virtual int id() = 0;
    };

    implementation in one plugin (s.l.):
    class Objekt2 : public IObjekt2
    {
    Q_OBJECT
    public:
    Objekt2( int id, QObject *parent = 0 ) : IObjekt2(id, parent) {}
    ~Objekt2() {}
    int id() { return m_id; }
    };

    If we write in the plugin that defines Objekt2:
    Qt Code:
    1. QObject *o = new Objekt2(199);
    2. IObjekt2 *obj = qobject_cast<IObjekt2 *>(o);
    To copy to clipboard, switch view to plain text mode 
    The "obj" will have correct pointer.

    But if we use the "o" instance in second plugin, and try to write
    Qt Code:
    1. IObjekt2 *obj = qobject_cast<IObjekt2 *>(o);
    To copy to clipboard, switch view to plain text mode 
    the result is 0 pointer.

    I found the reason in:
    Qt Code:
    1. QObject *QMetaObject::cast(QObject *obj) const
    2. {
    3. if (obj) {
    4. const QMetaObject *m = obj->metaObject();
    5. do {
    6. if (m == this)
    7. return const_cast<QObject*>(obj);
    8. } while ((m = m->d.superdata));
    9. }
    10. return 0;
    11. }
    To copy to clipboard, switch view to plain text mode 

    because qobject_cast is practicaly defined as:
    Qt Code:
    1. template <class T>
    2. inline T qobject_cast(QObject *object)
    3. {
    4. return static_cast<T>(reinterpret_cast<T>(0)->staticMetaObject.cast(object));
    5. }
    To copy to clipboard, switch view to plain text mode 

    What is important, MOC transforms Q_OBJECT macro to declaration of two static objects describing our class (one of the is const QMetaObject*staticMetaObject) and some methods.., and qobject_cast uses the "staticMetaObject" defined for our class and calls its cast(QObject*) method. This method goes throw all pointers to static objects that are defined for all classes in the inheritance tree of our class and if some pointer equals to THIS (= pointer to static object describing our class), it knows that QObject* can be static_casted to IObjekt2* without any problems....

    Now the question...

    Shouldn't there be something like:
    Qt Code:
    1. template <class T> T my_cast( QObject *object )
    2. {
    3. if (object)
    4. {
    5. const QMetaObject *m = object->metaObject();
    6. const QMetaObject *class_m = reinterpret_cast<T>(0)->staticMetaObject.d.superdata;
    7. do {
    8. if (m == class_m)
    9. return static_cast<T>(object);
    10. } while ((m = m->d.superdata));
    11. }
    12. return (T)0;
    13. }
    To copy to clipboard, switch view to plain text mode 
    that compares SUPERDATAs and not THIS pointer (pointer to static data)? The casting cross shared libraries is functional now... Isn't the example with SUPERDATA more general than the previous version?

    thanks for your opinion...

  2. #2
    Join Date
    Aug 2007
    Posts
    166
    Thanks
    16
    Thanked 14 Times in 14 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: qobject_cast<T> in shared libraries...

    I personally think that you should report your suggestion to the Qt guys, it will be nice to have it in Qt 4.5.

  3. #3
    Join Date
    Dec 2006
    Posts
    849
    Thanks
    6
    Thanked 163 Times in 151 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: qobject_cast<T> in shared libraries...

    This (known) "issue" (or feature, if you want; probably this implementation is faster and was chosen with purpose) can be worked around by having the common base class put inside a lib that both "parties" link against. That way there will be only one such metaobject and the qobject_cast will not fail.

    Still, reporting it to the trolls won't hurt.

    HTH
    PS: There are (some) compilers that internally use a string-compare for dynamic_cast, too.
    g++, however, uses (for efficiency reasons - again) a pointer comparison of the internal rtti object. Thus, dynamic_cast may (and with g++ does) suffer from across shared library issues, too.

  4. #4
    Join Date
    Dec 2008
    Posts
    29
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: qobject_cast<T> in shared libraries...

    Thanks for answer,

    Quote Originally Posted by caduel View Post
    This (known) "issue" (or feature, if you want; probably this implementation is faster and was chosen with purpose) can be worked around by having the common base class put inside a lib that both "parties" link against. That way there will be only one such metaobject and the qobject_cast will not fail.
    I thougth, that this common base class can be also QObject, because both sides (plugins) link against Qt libraries. Or am I wrong?

  5. #5
    Join Date
    Dec 2006
    Posts
    849
    Thanks
    6
    Thanked 163 Times in 151 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: qobject_cast<T> in shared libraries...

    No. (Only if you try the rather pointless qobject_cast<Qbject*>(...) ;-)

    If you do a qobject_cast<T*>(someObj) then the definition of T has to be in a common library. You must not have the header of T added in two .pro files' HEADERS-sections. Otherwise the Q_OBJECT macro will be moced and compiled multiple times. This would lead to multiple instances of the metaobject and the problem you noted.
    If you put the definition of T into a lib there will be only one metaobject (the one defined by the lib) and the qobject_cast will work as expected.

    HTH

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: qobject_cast<T> in shared libraries...

    Quote Originally Posted by seim View Post
    Shouldn't there be something like:
    (...)
    that compares SUPERDATAs and not THIS pointer (pointer to static data)?
    The cast compares the static meta object of a class it expects with the actual meta object of the object you pass to it.

    The casting cross shared libraries is functional now... Isn't the example with SUPERDATA more general than the previous version?
    qobject_cast across libraries works If you want to cast type A to type B you have to know both types when you make the cast. qobject_cast works because the inheritance data is stored in a "common base class" of all objects - QMetaObject tied to QObject. With dynamic_cast "castable" classes need to be known while compiling the actual class.

    So as far as I understand your issue, the problem is not with qobject_cast but actually with the way you make the cast. If qobject_cast hadn't worked across library boundaries, Designer wouldn't be able to handle custom widgets and the plugin infrastructure in Qt wouldn't work at all. If you use GCC (on Unix, it doesn't work with MinGW), you can use some switch that will enable resolving symbols in plugins against the main application which will allow you to define the interface in the main application only without actually referencing it anywhere in the plugin (which I understand currently poses the problem).



    By the way, comparing pointers to meta-objects is fine. Static objects have addresses too so that's not a problem.

  7. #7
    Join Date
    Dec 2008
    Posts
    29
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: qobject_cast<T> in shared libraries...

    Quote Originally Posted by caduel View Post
    You must not have the header of T added in two .pro files' HEADERS-sections. Otherwise the Q_OBJECT macro will be moced and compiled multiple times. This would lead to multiple instances of the metaobject and the problem you noted.
    Thank you, this is the key! Interface header file was included in both plugin projects and that led to 2x different static objects for "one class". Shame on me
    Last edited by seim; 31st December 2008 at 03:12.

  8. #8
    Join Date
    Dec 2008
    Posts
    29
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11

    Thumbs up Re: qobject_cast<T> in shared libraries...

    One more thing as a solution given by B.Poulain:

    "The problem come from the declaration of the
    class IObject without the macro Q_DECLARE_INTERFACE. This macro should
    be used for all objects exported outside the plugin.
    If you add it, everything works fine.

    If you look at the declaration of Q_DECLARE_INTERFACE, it use a slightly
    different approach to make qobject_cast working across library but
    without being dependant of the linker."

    The IObject header file has to be added in both .pro files.

    Thank you all, for your posts.


Similar Threads

  1. Deployment (shared libraries)
    By amagdy.ibrahim in forum Qt Programming
    Replies: 5
    Last Post: 26th June 2008, 21:55
  2. Related to Packaging of Qt4 Application
    By archanasubodh in forum Installation and Deployment
    Replies: 1
    Last Post: 21st March 2008, 14:55
  3. Qt 3.3 libraries
    By ToddAtWSU in forum Qt Programming
    Replies: 1
    Last Post: 21st December 2006, 17:25
  4. Shared lib template broken under linux ???
    By fullmetalcoder in forum Qt Programming
    Replies: 9
    Last Post: 26th April 2006, 20:05
  5. I got two problems when I used static compiled library of QT4
    By qintm in forum Installation and Deployment
    Replies: 8
    Last Post: 20th April 2006, 08:52

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.