This is a slightly OT C++ question, but since it's related to
wxWidgets (it's for wxLua) I hope someone might be able to help.
I'm using wxWidgets 2.8.10 in Linux, GTK2, gcc 4.3.2
In wxLua all of the C++ class objects are stored as void* pointers
(Lua is C), but with some extra data wrapped up to know the type. In
order to minimize the size of the bindings I do not declare all the
functions for each class, but use inheritance so that in the case of a
wxComboBox I will want to lookup many functions in the
wxItemContainerImmutable base class and call them from my void*
pointer cast to a wxItemContainerImmutable. This has always worked in
the past for other classes, but I am having trouble with
wxItemContainerImmutable in particular and I wonder if it is because
it is an abstract class (many of its functions are = 0; and have no
body)?
Can someone please confirm if the odd behavior is to be expected,
though unfortunate, and, if it's not too much trouble, briefly explain
why this is?
The class hierarchy for the wxComboBox is:
class WXDLLIMPEXP_CORE wxComboBox : public wxControl, public wxComboBoxBase
include/wx/gtk/combobox.h
class WXDLLEXPORT wxComboBoxBase : public wxItemContainer
include/wx/combobox.h
class WXDLLEXPORT wxItemContainer : public wxItemContainerImmutable
include/wx/ctrlsub.h
where the function GetCount() is declared as:
virtual unsigned int GetCount() const = 0;
The simplest incarnation of what I am trying to do is shown in the
diff to the minimal.cpp sample below and you can see the output it
prints. The reality is that it's not just getting the wrong value,
it's corrupting the stack and if you try to get more complicated
you'll eventually get a segfault.
$ ./minimal
wxComboBox::GetCount = 0
wxComboBox::GetCount = 0
wxItemContainerImmutable::GetCount = 737
$ diff -c minimal_2.8.10.cpp ../../../samples/minimal/minimal.cpp
*** minimal_2.8.10.cpp 2009-07-01 22:59:07.000000000 -0400
--- minimal.cpp 2009-07-01 23:12:08.000000000 -0400
***************
*** 141,146 ****
--- 141,157 ----
// main frame
// ----------------------------------------------------------------------------
+ void check_stuff(void * v)
+ {
+ wxComboBox* c = (wxComboBox*)v;
+ int cn = c->GetCount();
+ wxPrintf(wxT("wxComboBox::GetCount = %d\n"), cn);
+
+ wxItemContainerImmutable* i = (wxItemContainerImmutable*)v;
+ int in = i->GetCount();
+ wxPrintf(wxT("wxItemContainerImmutable::GetCount = %d\n"), in);
+ }
+
// frame constructor
MyFrame::MyFrame(const wxString& title)
: wxFrame(NULL, wxID_ANY, title)
***************
*** 172,177 ****
--- 183,192 ----
CreateStatusBar(2);
SetStatusText(_T("Welcome to wxWidgets!"));
#endif // wxUSE_STATUSBAR
+
+ wxComboBox* c = new wxComboBox(this, -1, wxT("Hello"));
+ wxPrintf(wxT("wxComboBox::GetCount = %d\n"), c->GetCount());
+ check_stuff(c);
}
Thanks for any help,
John
Just to be sure, a confirmation of my suspicions would be great and if
possible a workaround.
Below is the output from the diff to the minimal.cpp sample and you
see that the wxControl's GetLabel() function is called in both cases.
The proof is that include/wx/gtk/window.h has wxWindow::GetLabel() {
return wxEmptyString; }.
$ ./minimal
wxComboBox::GetCount = 0
wxComboBox::GetCount = 0
wxItemContainerImmutable::GetCount = 737
wxWindow::GetLabel 'Hello', wxControl::GetLabel 'Hello'
$ diff -c minimal_2.8.10.cpp ../../../samples/minimal/minimal.cpp
*** minimal_2.8.10.cpp 2009-07-01 22:59:07.000000000 -0400
--- minimal.cpp 2009-07-02 00:46:03.000000000 -0400
***************
*** 141,146 ****
--- 141,161 ----
// main frame
// ----------------------------------------------------------------------------
+ void check_stuff(void * v_combo, void *v_ctrl)
+ {
+ wxComboBox* combo = (wxComboBox*)v_combo;
+ int cn = combo->GetCount();
+ wxPrintf(wxT("wxComboBox::GetCount = %d\n"), cn);
+
+ wxItemContainerImmutable* immut = (wxItemContainerImmutable*)v_combo;
+ int in = immut->GetCount();
+ wxPrintf(wxT("wxItemContainerImmutable::GetCount = %d\n"), in);
+
+ wxWindow* win = (wxWindow*)v_ctrl;
+ wxControl* ctrl = (wxControl*)v_ctrl;
+ wxPrintf(wxT("wxWindow::GetLabel '%s', wxControl::GetLabel
'%s'\n"), win->GetLabel().c_str(), ctrl->GetLabel().c_str());
+ }
+
// frame constructor
MyFrame::MyFrame(const wxString& title)
: wxFrame(NULL, wxID_ANY, title)
***************
*** 172,177 ****
--- 187,198 ----
CreateStatusBar(2);
SetStatusText(_T("Welcome to wxWidgets!"));
#endif // wxUSE_STATUSBAR
+
+ wxControl* ctrl = new wxControl(this, -1);
+ ctrl->SetLabel(wxT("Hello"));
+ wxComboBox* c = new wxComboBox(this, -1, wxT("Hello"));
+ wxPrintf(wxT("wxComboBox::GetCount = %d\n"), c->GetCount());
+ check_stuff(c, ctrl);
}
Thanks,
John
Thanks,
John
JL> wxComboBox I will want to lookup many functions in the
JL> wxItemContainerImmutable base class and call them from my void*
JL> pointer cast to a wxItemContainerImmutable.
How do you perform the cast? If you use C style cast, it has no chance of
working with anything but the simplest possible class hierarchy without
multiple nor virtual base classes. In wxComboBox case (or with any class
having multiple base classes) the values of void* pointers to different
base classes is different. So if you store a wxComboBox* as void* and then
just cast it to wxItemContainer* it will clearly never work.
What you need to do is, assuming that you have stashed somewhere a
void *p = combobox;
wxItemContainer *container = static_cast<wxComboBox *>(p);
The static_cast<> here actually does give the same result as a C style cast
but it's more clear. The important thing is that you can only correctly
cast p to wxComboBox and not to wxItemContainer!
Regards,
VZ
--
TT-Solutions: wxWidgets consultancy and technical support
http://www.tt-solutions.com/
To continue what Vadim mentions here, I came across an MS tech note
some time ago (I think that's where I saw it, might have been a
reference to the C++ standard) in reference to storing pointers in
untyped containers (void*, LPARAM, ...). Basically, what you need to
make sure you do is to always cast the pointer back to what you put
it in as. Since I usually have some type of hierarchy, I always
create a helper function (this may be in the dialog, or it may extend
the list/etc control, depends on my need):
void SomeClass::SetData(MyBaseType* data) { ...SetData((void*)data); }
MyBaseType* SomeClass::GetData() {
reinterpret_cast<MyBaseType*>(...GetData()); }
...
obj.SetData(new MyDerivedType());
MyDerivedType* data = dynamic_cast<MyDerivedType*>(obj.GetData());
...
This way I am guaranteed to be working with consistent data.
Dave
With all that casting, things are going to go wrong. You're invoking undefined behavior in C++ (sorry, I don't remember the reference). If you pass a pointer via void*, you must cast that back to whatever it was originally cast from. Casting to anything else is undefined. No matter the inheritance.
So, if you have:
class A: public wxObject {};
wxObject* obj = new A();
void* v = obj;
then, the only valid way to get the pointer back from 'v' is:
A* obj2 = dynamic_cast<A*>(reinterpret_cast<wxObject*>(v));
casting v directing to A* is undefined. It may work, it may not.
Dave Connet
They are quite different. reinterpret_cast is like a C-style cast. "I said it's this type so it is". static_cast will only work on related types. void* and A* are not related.
What I was referring to above (it may/maynot work) was if you do:
A* obj2 = reinterpret_cast<A*>(v);
you are invoking undefined behavior. (Because I set the value of 'v' to a wxObject*)
Dave
On Mon, Jul 27, 2009 at 12:31 PM, David
Connet<dc...@agilityrecordbook.com> wrote:
>
>> From: andre arpin <mcm...@gmail.com>
>> 4 immut =
>> dynamic_cast<wxItemContainerImmutable*>
>> (static_cast<wxObject*>(v_combo));
>> 5 int in = immut->GetCount();
So, this works and I could do this so long as I can guarantee that the
first base class in the inheritance hierarchy is eventually derived
from a wxObject, but as Dave says below, the behavior is undefined and
might be compiler dependent. hrm... no good.
>
> With all that casting, things are going to go wrong. You're invoking undefined behavior in C++ (sorry, I don't remember the reference). If you pass a pointer via void*, you must cast that back to whatever it was originally cast from. Casting to anything else is undefined. No matter the inheritance.
This is too bad, I'm really just trying to save code by having one
wxLua binding function for each C++ class member function. It does
seem like I will have to duplicate all the functions inherited from
the second or higher base classes simply to be able to cast the void*
pointer to the correct type.
------------------------------------------------------
I tried to play around with template functions to do the casting since
I read in a forum that template functions know more about their type
than objects somehow, but the comment I read was pretty vague. In any
case I can't seem to get it right, probably because it's simply not
allowed.
Psuedo code that I don't imagine can ever be made to work. I apologize
if the code below borders on stupidity, but it's all I can think of.
template <class T> T* cast_func(void* p) { return static_cast<T*>p; }
struct wxLuaBindClass // store info about each class, we already do this
{
const char* class_name;
int data_type;
...
cast_func* f; // add a function to cast a void* to obj of the right type
};
// Create an instance of the wxLuaBindClass struct for each class that
we will push
// a pointer to along with the void* pointer to our object to describe
what the object is.
// note that we already do this for type checking, I just want to add
the "cast_func" to it
wxLuaBindClass wxComboBoxData = { "wxComboBox", 100, &cast_func<wxComboBox> }
int ABindingFuncCalledByLuaFromYourScriptForASinglewxItemContainerImmutableFunction(lua_State*
L)
{
// generically get the wxLuaBindClass struct above, which may be
the wxComboBoxData we created
// or for some other class derived from a wxItemContainerImmutable
void* void_wxlBindClass =
get_bindclassdata_from_lua_we_store_with_the_object_on_the_stack(...);
wxLuaBindClass* wxlBindClass =
static_cast<wxLuaBindClass*>void_wxlBindClass;
// get the void* pointer to the object off the Lua stack (type
checking code to
// guarantee it's derived from a wxItemContainerImmutable not shown)
void* void_obj = get_object_as_voidptr_from_the_lua_stack(...);
// ...and finally call the magic function that will cast the
object to its actual type is called.
// Since this is a generic function for ALL
wxItemContainerImmutable derived
// classes we can't specialize for any particular derived class and that
// is why I want to tuck the function into the wxLuaBindClass struct.
wxItemContainerImmutable* obj = wxlBindClass->f(void_obj);
// Ta-Da! we have the object cast correctly and we can call our function!
obj->TheFunctionTheScriptWantsToCall(...);
}
Well, I dunno. Unless someone can explain how to do something like the
above, I'm pretty much settled on generating binding functions for
each C++ class to correctly cast the void* pointer to the object.
Thanks for any insight!
John
JL> Well, I dunno. Unless someone can explain how to do something like the
JL> above,
Sorry, I have trouble understanding what is "something like the above"
exactly. If this means being able to restore the pointer to any most
derived class from a simple void*, then this is indeed impossible without
keeping more information, but this seems obvious, so you probably mean
something else -- but what?
There are cases where you must use reinterpret_cast. For instance all
windows controls that allow you to stash data (lists, trees, etc) all
store that data as a DWORD_PTR. So you must reinterpret_cast it into
something else. (FYI: When I say 'reinterpret_cast', I'm including
all C-style casts in that statement)
Using casts is fine - you just have to understand why you're casting.
And wxWidgets use should be fine - the issues I was pointing out,
they handle by taking a certain type (like wxTreeItemData*) and
returning that. So any internal casts should be simply taking that
(note, I haven't looked), cast to void*, and then casting that back
to wxTreeItemData. The fact that your type is a
wxTreeItemDataDerived* doesn't matter, as it is effectively cast to a
wxTreeItemData* by calling the SetItemData api. [Note, there is one
class I know of that breaks down with storing data (I'm using 2.8.10)
- wxListCtrl. This takes a 'long'. On win64, that's not big enough,
so you can't store pointers. (On windows/Win64, a long is still 32 bits)]
Also, you mentioned before that using the same compiler is ok - umm,
no it's not. It >might< be working, but the compiler writer is
allowed to break that. That's what undefined behavior means. So it's
best to always be in the habit of casting thru a void* using the same
type. (There's a technote on MSDN somewhere that specifically
mentions this in reference to storing objects in windows classes -
that's how I first became aware of it.)
Dave
Actually, I do/did mean to ask how and if it is possible to
dynamically cast a void* pointer to a specified type to be determined
at runtime. The example was to ask if it is possible to store a
pointer in a struct to some sort of casting function that you could
call whenever desired to cast the void* pointer appropriately and
dynamically.
But alas, it doesn't seem possible. In any case, not being able to do
it isn't the end of the world, just a little more code.
Thanks,
John
JL> Actually, I do/did mean to ask how and if it is possible to
JL> dynamically cast a void* pointer to a specified type to be determined
JL> at runtime. The example was to ask if it is possible to store a
JL> pointer in a struct to some sort of casting function that you could
JL> call whenever desired to cast the void* pointer appropriately and
JL> dynamically.
This depends on how the original void* pointer came into being. But if it
was obtained by static_cast<void *>(objOfTypeT) then you can always
retrieve it via static_cast<T *>. Of course, the trouble is that you need
to specify T here at compile-time so to get this behaviour at run-time you
need to use virtual functions, e.g. have something like this
struct TypeInfoBase {
virtual void *UpCast(void *) = 0;
};
template <class T>
struct TypeInfo : TypeInfoBase {
virtual void *UpCast(void *p)
{ return static_cast<T *>(p); }
};
and store TypeInfo<T> objects indexed by, say, name of T, in your table.
I've been playing with this and I'm not sure I understand how to make
it work. If I add it to the minimal sample code from before I get the
wrong number from the wxItemContainerImmutable::GetCount() function
from a wxComboBox since even though the TypeInfo::UpCast() function
correctly casts it internally the compiler forgets all about that when
it converts it back to a void* for the return value.
void check_stuff(void * v_combo, void *v_ctrl)
{
TypeInfo<wxComboBox> ti_combo;
wxItemContainerImmutable* immut1 =
static_cast<wxItemContainerImmutable*>(ti_combo.UpCast(v_combo));
int immut1_c = immut1->GetCount();
wxPrintf(wxT("wxItemContainerImmutable::GetCount1 = %d\n"), immut1_c);
}
Thanks,
John
JL> I've been playing with this and I'm not sure I understand how to make
JL> it work. If I add it to the minimal sample code from before I get the
JL> wrong number from the wxItemContainerImmutable::GetCount() function
JL> from a wxComboBox since even though the TypeInfo::UpCast() function
JL> correctly casts it internally the compiler forgets all about that when
JL> it converts it back to a void* for the return value.
JL>
JL> void check_stuff(void * v_combo, void *v_ctrl)
JL> {
JL> TypeInfo<wxComboBox> ti_combo;
JL>
JL> wxItemContainerImmutable* immut1 =
JL> static_cast<wxItemContainerImmutable*>(ti_combo.UpCast(v_combo));
JL> int immut1_c = immut1->GetCount();
JL> wxPrintf(wxT("wxItemContainerImmutable::GetCount1 = %d\n"), immut1_c);
JL> }
I see... This indeed doesn't work in this case, you need to use the
pointer as wxComboBox and not wxItemContainerImmutable. Of course, in this
example you could just replace the assignment line with
wxItemContainerImmutable* immut1 =
static_cast<wxComboBox*>(ti_combo.UpCast(v_combo));
and it would work but this is not a general solution unfortunately...