RTTI, dynamic casting, wxClientData questions

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
User avatar
Disch
Experienced Solver
Experienced Solver
Posts: 99
Joined: Wed Oct 17, 2007 2:01 am

RTTI, dynamic casting, wxClientData questions

Post by Disch »

I'm trying to tie some data to entries in a list box. I'm doing this by deriving a class (called SourceInfo) from wxClientData, and supplying it to my call to Append() when adding items to the list box.

I had problems downcasting from wxClientData* to SourceInfo*. I ran through the RTTI section in the docs and I got a solution which appears to be working -- but RTTI is all kind of new ground for me, I would LOVE to have confirmation that I'm doing this properly from someone who knows all the rules regarding this kind of thing. I'd hate to have this come back and bite me in the rump when I think I'm doing everything kosher.

Code: Select all

// my header file
class SourceInfo : public wxClientData, public wxObject
{
public:
    DECLARE_DYNAMIC_CLASS(SourceInfo)

    //  .. vars and junk here
};

Code: Select all

// my cpp file

IMPLEMENT_DYNAMIC_CLASS(SourceInfo,wxObject)

Code: Select all

// attempting to downcast
SourceInfo* inf = wxDynamicCast(mylistbox->GetClientObject(index),SourceInfo);
I had to derive my class from both wxClientData (so that I could put it in the list box), and wxObject (which apparently is needed for RTTI stuff). Is this the right way to do it?

Thanks in advance!
closer
In need of some credit
In need of some credit
Posts: 9
Joined: Thu Feb 05, 2009 11:16 am
Location: Taipei, Taiwan

Post by closer »

Disch,

I'm not quite familiar with RTTI either, but I don't think you have to derive your class from wxObject. (wxClientData is already derived from wxObject)

You should try this:

Code: Select all

// header file
class SourceInfo : public wxClientData
{
public:
    DECLARE_DYNAMIC_CLASS(SourceInfo)

    //  .. vars and junk here
};



// cpp file

IMPLEMENT_DYNAMIC_CLASS(SourceInfo,wxClientData)
You may want to check this page for the usage of RTTI-related macros.
User avatar
Disch
Experienced Solver
Experienced Solver
Posts: 99
Joined: Wed Oct 17, 2007 2:01 am

Post by Disch »

closer wrote:I don't think you have to derive your class from wxObject. (wxClientData is already derived from wxObject)
The docs make no mention of that. Parent classes are usually listed in the docs in a "derived from" section, I see no such section on wxClientData's page. This can only lead me to assume wxClientData has no parent classes.

Though I haven't looked at the source, I suppose I could be wrong.
You should try this:
I just did -- no go. I get "error C2039: 'ms_classInfo' : is not a member of 'wxClientData'" and other similar errors. This is what led me to derive from wxObject in the first place, iirc.

I've checked the list of RTTI macros and whatnot, but I still haven't really seen a example of the proper way to do something like this anywhere in the docs. The way I'm doing it appears to be working fine though -- so maybe I shouldn't sweat it?

Thanks for the response. :)
closer
In need of some credit
In need of some credit
Posts: 9
Joined: Thu Feb 05, 2009 11:16 am
Location: Taipei, Taiwan

Post by closer »

Ah, I was wrong.
I misunderstood the content of the documents and thought that wxClienData is derived from wxEvtHandler.

I apologize for my misleading information.

And since that doesn't work, the multiple inheritance is also the only way I can think of so far....
tan
wxWorld Domination!
wxWorld Domination!
Posts: 1471
Joined: Tue Nov 14, 2006 7:58 am
Location: Saint-Petersburg, Russia

Post by tan »

Hi.
closer wrote: And since that doesn't work, the multiple inheritance is also the only way I can think of so far....
It not absolutely so :) you can use "native" C++ means:

Code: Select all

// attempting to downcast
SourceInfo* inf = dynamic_cast<SourceInfo*>(mylistbox->GetClientObject(index));
if( inf )  // Ok, it is real SourceInfo
{
...
}
else       // Fail, it is any another type
{
...
}
OS: Windows XP Pro
Compiler: MSVC++ 7.1
wxWidgets: 2.8.10
closer
In need of some credit
In need of some credit
Posts: 9
Joined: Thu Feb 05, 2009 11:16 am
Location: Taipei, Taiwan

Post by closer »

Well, I found that too after posting the previous post. :) I was stuck with the idea that "use wxWidgets' RTTI functions only".

I did some tests in VC++ 2008 Express and listed some points worth to be noticed:

1. If dynamic_cast's are used, the "RTTI support" option of the compiler should be turned on. Otherwise there will be unpredictable results. (In my case, the application terminated without any error messages)

2. Since the result of dynamic_cast might be null, the result must be checked before using it. (Just like tan's example)

3. If you don't want to turn on RTTI support, and you know that the casting can't be wrong, you can use static_cast (or C-style casting) -- although doing this is less safer when the situation becomes more complicated.

Code: Select all

SourceInfo* inf;
inf = static_cast<SourceInfo*>(mylistbox->GetClientObject(index));
// or
inf = (SourceInfo*)mylistbox->GetClientObject(index);
User avatar
Disch
Experienced Solver
Experienced Solver
Posts: 99
Joined: Wed Oct 17, 2007 2:01 am

Post by Disch »

Yeah I suppose I could just static_cast it, or use C++'s normal dynamic_cast.

But assuming I want to stick with the wx casting stuff -- am I doing it right? That's really all I'm wondering. This is more about me trying to understand the 'proper' way to apply wx here, and not so much about getting it to work -- I already had it working.
Post Reply