Failing qobject_cast
-
Hi guys, it might be because I am completely asleep... 3:15am
I thought of using the metaObject to verify my type beforehand.
Yet the className seems ok, but the cast fails... Any clue?@
virtual bool applyFilter(Model* model, RichParameterSet& par, CallBackPos* cb=0){
qDebug() << model->metaObject()->className();
SurfaceMeshModel* mesh = qobject_cast<SurfaceMeshModel*>(model);
if(!mesh){
qDebug("MASSIVE FAIL.. TERMINATING");
exit(-1);
return false;
}
....
}
@output:
@
SurfaceMeshModel
MASSIVE FAIL.. TERMINATING
@These are the core definitions:
@
class SurfaceMeshModel : public Model, public Surface_mesh{
Q_OBJECT
Q_INTERFACES(Model)
....
@@
class Model : public QObject{
Q_OBJECT
....
};
Q_DECLARE_INTERFACE(Model, "starlab.interface.Model/1.0")
@ -
I know this is a weird question but are you sure your model is not NULL in the first place ?
Plus, why do you use qobject_cast here, when a static_cast would be much more efficient ? -
[quote author="rcari" date="1319722285"]I know this is a weird question but are you sure your model is not NULL in the first place ?[/quote]
This is actually a good question.
[quote]Plus, why do you use qobject_cast here, when a static_cast would be much more efficient ?[/quote]qobject_cast() simply is safer. If this particular cast turns out to be a performance hog, then it is time to start thinking about static_cast()ing. Remember that premature optimization is the root of all evil, and that more programming sins are committed in the name of performance than any other, including blind stupidity.
-
[quote author="Franzk" date="1319726749"]
[quote author="rcari" date="1319722285"]I know this is a weird question but are you sure your model is not NULL in the first place ?[/quote]This is actually a good question.
[/quote]I don't think so since tallia1 calls model->metaObject(). If model == 0 the app would crash at this point, not later.
-
That was my point however, some compiler magic could lead to cases where it wouldn't even lookup the vtable to place the call for metaObject(), thus not requiring to dereference the pointer... I agree that would be serious trickery...
-
Hmm, well spotted. I think you need to dig into the qobject_cast to see what's going wrong.
-
Is the Surface_mesh class based on QObject too?
And what is the output of this snippet:
@
const QMetaObject *mo = model->metaObject();
while(mo) {
qDebug() << mo->className();
mo = mo->superClass();
}
@ -
I just spent my morning trying to figure it out. Indeed rcari
is right, I didn't need to to qobject_cast. I was using it mostly
because I wanted to use introspection to see whether I was
doing something wrong...An important note is that the two classes are located in
different dynamically loaded libraries... so I am not sure
I can use the C++ dynamic_cast there...I will try what you suggest Volker.
-
qobject_cast should be safe over DLL boundaries - that's at least what the docs state. You did not answer whether the Surface_mesh class is based on QObject too?
-
Hi Volker,
Indeed, that's why I was using qobject_cast at a certain point (and going back to it right now)
And to answer your question, yes it is:
@
class SurfaceMeshModel : public Model, public Surface_mesh{
Q_OBJECT
Q_INTERFACES(Model)
...
@ -
That was clear, SurfaceMeshModel inherits Model which eventually inherits QObject.
The question is, does your second base class, Surface_mesh, inherit QObject too (directly or indirectly) - i.e. what's the class hierarchy for the Surface_mesh class?
-
Oh sorry, misunderstood your question. Surface_mesh is an external library and not Qt, so no, it doesn't know anything about Qt at all..
-
Ok. That's good. It's not allowed to inherit QObject via two different paths.
So, what's the output of that little debug loop I pasted earlier?
-
And this is the output of this snippet:
@
const QMetaObject *mo = model->metaObject();
qDebug() << "Hierarchy: ";
while(mo) {
qDebug() << " " << mo->className();
mo = mo->superClass();
}
@Output:
@
Hierarchy:
SurfaceMeshModel
Model
QObject
MASSIVE FAIL.. TERMINATING
@ -
This is really strange. Can you boil down the code to small, yet complete test case that demonstrates the error? I don't have any clue, whats going wrong here. BTW: what operating system are you on?
-
I am on OSX Lion. I isolated the problem even more. Look at the snippet below:
@
SurfaceMeshModel* model = new SurfaceMeshModel(path);Model* retval = qobject_cast<Model*>(model);
qDebug() << "Conversion Mesh=>Model: " << (retval?"success":"failed");SurfaceMeshModel* mesh = qobject_cast<SurfaceMeshModel*>(retval);
qDebug() << "Conversion Model=>Mesh: " << (mesh?"success":"failed");
@And the output is ...
@
Conversion Mesh=>Model: success
Conversion Model=>Mesh: failed
@ -
And now I just replaced the qobject_cast with a dynamic cast. I get a "success, success" in the test above, but a fail when it goes across the DLL boundaries (the snipped above was within the boundaries of a single compiled element).
-
Just for curiosity, what's the output of
@
qDebug() << "model :" << model;
qDebug() << "retval:" << retval;
qDebug() << "mesh :" << mesh;
@ -
By using both qobject_cast:
@
Conversion Mesh=>Model: success
Conversion Model=>Mesh: failed
model : SurfaceMeshModel(0x1023b3fc0)
retval: SurfaceMeshModel(0x1023b3fc0)
mesh : QObject(0x0)
@ -
Weird. It's completely weird.
Just a another blind guess: may it be, that you happen to load two different versions of the Qt libs via the two libraries (resp. your app and library)? This may cause trouble too.
You can check this with the otool tool on the mac and some dyld debug settings:
@
export DYLD_PRINT_LIBRARIES=1
/path/to/your/Program.app/Contents/MacOS/Program 2>LOG-libraries.txt
unset DYLD_PRINT_LIBRARIES
@Then check LOG-libraries.txt for the loaded Qt libraries:
@
grep Qt LOG-libraries.txt
@It must not print libraries from different paths.