PDA

View Full Version : qobject_cast fails across dynamic library boundaries



JPNaude
4th December 2008, 11:27
Hi

I'm sitting with a problem where a qobject_cast fails when doing a cast across a DLL boundary.

I have a base class:



class Variable : public QObject
{
Q_OBJECT

public:
Variable(QObject* parent = 0);
~Variable();
}


and a class which inherits Variable:


class MatrixReal : public Variable
{
Q_OBJECT

public:
MatrixReal();
}


I create a MatrixReal* instance and cast it to a Variable*. When casting Variable* to MatrixReal* again later on in the same DLL it works. However if I send this Variable* to a different DLL and try to cast to MatrixReal* there it fails.

Any ideas on how to get this working would be much appreciated.

Thanks,
Jaco

jpn
4th December 2008, 17:09
Could you show relevant pieces of the code?

caduel
4th December 2008, 17:33
Search the forum for other threads on this topic.

Make sure that the header of the class you wish to qobject_cast to, is not processed by moc in both the DLLs (i.e. it must not be in both .pro files' HEADERS sections).

JPNaude
5th December 2008, 08:11
Hi

Thanks for the response. I searched the forum and found a good post explaining the operation of qobject_cast and it explains why it fails.

I also read on the proposed solutions there:
1) Using inherits() : This will not work for me since I up from a base class to a class that inherits the base class. As I understand inherits() works the other way around?
2) Creating a library with the classes in it. : I would use this as a last resort really.

For now, I think I found a different solution using reinterpret_cast. It works for now, but I'm not sure if it will work if there are more child classes present. Let me first show my code:



if (variable) {
if (reinterpret_cast<MatrixReal*> (variable))
QMessageBox::warning(0,"Cast successful","Cast successful");
else
QMessageBox::warning(0,"Cast failed","Cast failed");
}


Now the question is, will this work if there is for example a MatrixComplex class as well? I would then have something like:



if (variable) {
if (reinterpret_cast<MatrixReal*> (variable))
QMessageBox::warning(0,"Cast successful","Cast successful to real matrix");
else if (reinterpret_cast<MatrixComplex*> (variable))
QMessageBox::warning(0,"Cast successful","Cast successful to complex matrix");
else
QMessageBox::warning(0,"Cast failed","Cast failed");
}


Will this still work? I guess the answer will be that this is a bad implementation since I read everywhere that reinterpret_cast is unsafe.

If needed I can post more code and look at an alternative way of doing this. I can also give more details of why I need to do these casts in my application.

Thanks,
Jaco

caduel
5th December 2008, 10:49
reinterpret_cast does NOT check if the argument is of a type, but rather tells the compiler that "you (the user) knows what he is doing" and it should just treat the type as if it was of the type you are casting to.

So, no, you may not replace a qobject_cast that way (except you are not interested in the testing part of the cast).

d_stranz
10th December 2008, 04:15
I believe that dynamic_cast -does- check that the argument is of the template type, and will return null if the cast fails. I've written some very hairy templated dynamic_cast code that depends on exactly this if / else if / else heirarchical behavior, and it works as expected - the dynamic casting cascades down the conditionals until one of the casts succeeds and returns a non-null result.

Use of dynamic_cast<> does require that you compile with the right flags to turn on run time type identification if your compiler doesn't do it by default.

As for qobject_cast, I have never quite understood why the trolls have felt the need to reinvent wheels that are already working quite well within the Standard C++ Library.

caduel
10th December 2008, 07:39
dynamic_cast does NOT (necessarily) work across shared libraries.
From experience: when you (try to) dynamic_cast a templated-type across shared libs with gcc, you are in trouble.
qobject_cast will work more often than dynamic_cast (usually). But (see threads) has its limitations, too.

JPNaude
10th December 2008, 09:00
Thanks for all the replies.

I actually have an identifier in my Variable base class which indicates which type of variable it is. Thus I will use this for the type checking and then do a reinterpret_cast once I know what type it is.

This might not be the optimal way, but my Variable base class need to keep this information for other purposes as well, so I actually had all the information I needed without realizing it.

Thanks again,
Jaco

wysota
10th December 2008, 09:34
Could you show us how exactly did you try to use qobject_cast? What does this return when called in both DLLs?


qDebug() << "I am a " << MatrixReal::staticMetaObject().className();
const QMetaObject *mo = MatrixReal::staticMetaObject().superClass();
while(mo){
qDebug() << "It's superClass is" << mo->className();
mo = mo->superClass();
}

seim
30th December 2008, 17:36
I didn't see your question thread, so I've described the reason and solution of your (my :)) problem in separate thread (http://www.qtcentre.org/forum/f-qt-programming-2/t-qobject-castt-in-shared-libraries-17799.html)..