5

I'm reading ``C++ GUI Programming with Qt 4", where I found the following statement

Unlike the Standard C++ dynamic_cast(), Qt’s qobject_cast() works correctly across dynamic library boundaries.

A similar statement appears in the official Qt documentation at

https://doc.qt.io/qt-5/qobject.html#qobject_cast

What does it mean? Where exactly we cannot use dynamic_cast in C++ ? And what about virtual functions? Is it safe to use them with dynamically linked libraries?

Adrian
  • 987
  • 5
  • 13
  • 3
    Possible duplicate of [dynamic\_cast returns NULL but it shouldn't](https://stackoverflow.com/questions/1964746/dynamic-cast-returns-null-but-it-shouldnt) – G.M. Jul 01 '19 at 11:04
  • 2
    @G.M. Well, the only answer to that question simply says ``Basically, RTTI is unreliable across module boundaries," while I'm asking for explanation what does it mean exactly (I'm not an experienced programmer). – Adrian Jul 01 '19 at 11:16
  • At least, if you can make a meager interface using only C ABI, your code will be more portable and robust. I generally try to avoid passing C++ objects and anything non-C across library boundaries. Same goes for exceptions. Also, meager interfaces reduce coupling between subsystems. – Erik Alapää Jul 01 '19 at 11:30

1 Answers1

7

In concept, dynamic_cast can work across module boundaries. But, some compilers/linkers cut corners in the name of performance. One of the ways to improve performance when loading shared libraries is to make as few symbols visible to other libraries as possible. This reduces the amount of work the loader has to do because it doesn't have to resolve as many symbols. RTTI symbols are on the chopping block and are among those not exposed to other modules by default. GCC's documentation describes this and the workaround here.

Unfortunately, this makes things a mess when it comes to RTTI. The module that constructed an object and the one performing the dynamic_cast might hold their own, otherwise identical, RTTI symbols for a type. This makes them appear as different types when the dynamic_cast is performed in a different module, causing dynamic_cast to unexpectedly return nullptr, or throw std::bad_cast for references.

Special care is required when linking and when calling dlopen() for the loader to know to resolve RTTI symbols between modules on module load.

Also, historically Qt has supported platforms which either do not support RTTI, or where RTTI would have too much of an overhead. So, qobject_cast was invented to remove the reliance on RTTI altogether while still providing a way to cast between polymorphic types.

To answer your other questions:

  • You can use dynamic_cast anywhere RTTI is available but dynamic linking can make this difficult.
  • Virtual functions work fine in these scenarios as the loader will resolve the symbols of functions.
Sean Cline
  • 6,979
  • 1
  • 37
  • 50