tags:

views:

582

answers:

9

I'm building a GUI class for C++ and dealing a lot with pointers. An example call:

mainGui.activeWindow->activeWidget->init();

My problem here is that I want to cast the activeWidget pointer to another type. activeWidget is of type GUI_BASE. Derived from BASE I have other classes, such as GUI_BUTTON and GUI_TEXTBOX. I want to cast the activeWidget pointer from GUI_BASE to GUI_TEXTBOX. I assume it would look something like this:

(GUI_TEXTBOX*)(mainGui.activeWindow->activeWidget)->function();

This isn't working, because the compiler still thinks the pointer is of type GUI_BASE. The following bit of code does work, however:

GUI_TEXTBOX *textbox_pointer;
textbox_pointer = (GUI_TEXTBOX*)mainGui.activeWindow->activeWidget;
textbox_pointer->function();

I'm hoping my problem here is just a syntax issue. Thanks for the help :)

+3  A: 

You just need more parentheses:

((GUI_TEXTBOX*)(mainGui.activeWindow->activeWidget))->function();

Actually, this would work too:

((GUI_TEXTBOX*)mainGui.activeWindow->activeWidget)->function();
Greg Hewgill
You beat me by seconds!
Paul Tomblin
A: 
((GUI_TEXTBOX*)(mainGui.activeWindow->activeWidget))->function();
Paul Tomblin
+18  A: 

The problem is that casts have lower precedence than the . -> () [] operators. You'll have to use a C++ style cast or add extra parentheses:

((GUI_TEXTBOX*)mainGui.activeWindow->activeWidget)->function();  // Extra parentheses
dynamic_cast<GUI_TEXTBOX*>(mainGui.activeWindow->activeWidget)->function();  // C++ style cast
Adam Rosenfield
If GUI_TEXTBOX is derived from GUI_BASE you should be using dynamic_cast<>()
Martin York
Whoops, good call - thanks.
Adam Rosenfield
And checking to make sure the value is not NULL!
Martin York
Well presumably the OP already knows that the widget is a GUI_TEXTBOX - otherwise, his original code could silently malfunction and have strange errors later; at least with dynamic_cast it'll fail-fast.
Adam Rosenfield
Adam. for fail fast, first dereference it, and then cast to a reference. so that it will throw std::bad_cast then. as it is now, you will get a null pointer for a bad cast and it doesn't crash necassarily
Johannes Schaub - litb
+2  A: 

As others noted:

((GUI_TEXTBOX*)(mainGui.activeWindow->activeWidget))->function();

The reason is that the -> operator has a higher precedence than the type casting.


I'll put another plug in here for Steve Oualline's rule from "Practical C":

There are fifteen precedence rules in C (&& comes before || comes before ?:). The practical programmer reduces these to two:

1) Multiplication and division come before addition and subtraction.

2) Put parentheses around everything else.


And a final note: downcasts can be dangerous, see Martin York's answer for information on using dynamic_cast<> to perform the cast safely.

Michael Burr
I learned C++ from Practical C++ and have derived immeasurable benefit from Oualline's precedence rules. Memorizing esoteria is for fools.
toast
A: 

-> has a higher precedence than (cast), so the member access is being done before the cast. See here for operator precedence: http://www.cppreference.com/wiki/operator_precedence

As stated above, you need more parentheses.

FigBug
A: 

It's a matter of order of operators (operator precedence). Consider the code you were trying that didn't work:

(GUI_TEXTBOX*)(mainGui.activeWindow->activeWidget)->function();

Here, the -> operator takes higher precedence than your cast. That's why your other code sample works. In the other sample, you explicitly cast first, then call the function. To make it more streamlined try adding another set of parenthesis so that the code looks like:

((GUI_TEXTBOX*)(mainGui.activeWindow->activeWidget))->function();

Brian
+8  A: 

You should not be using the C style cast.

You need to use the C++ dynamic cast. This will then allow you to test that the object is actually a GUI_TEXTBOX before you call the method on it.

GUI_TEXTBOX* textboxPointer  = dynamic_cast<GUI_TEXTBOX*>(mainGui.activeWindow->activeWidget);
if (textboxPointer)
{
     // If activeWidget is not a text box then dynamic_cast
     // will return a NULL.
     textboxPointer->textBoxMethod();
}

// or 

dynamic_cast<GUI_TEXTBOX&>(*mainGui.activeWindow->activeWidget).textBoxMethod();

// This will throw bad_cast if the activeWidget is not a GUI_TEXTBOX

Note the C style cast and reinterpret_cast<>() are not guaranteed to work in this situation (Though on most compilers they will [but this is just an aspect of the implementation and you are getting lucky]). All bets are off if the object assigned to activeWidget actually uses multiple inheritance, in this situation you will start to see strange errors with most compilers if you do not use dynamic_cast<>().

Martin York
A: 
if( GUI_TEXTBOX* ptr = 
      dynamic_cast<GUI_TEXTBOX *>(mainGui.activeWindow->activeWidget) )
{
   ptr->function();
}

The reason you want to do that is because the pointer you are trying to cast may not actually point to a GUI_TEXTBOX object and you want to make sure it does before calling textbox methods on it. C++'s dynamic cast is what you need for this.

carleeto
A: 

There are two strategies. One is "fail fast": If you cast to the wrong type, then you will have an exception thrown, so you will notice immediately that you cast to the wrong type. Another one is "run fast": No checking of the destination type of the cast is done. This cast should only be used if you know that you can't be wrong or if you don't have a polymorphic type with the base or the derived. I recommend the following depending on your needs (remember to keep const when you cast):

dynamic_cast<GUI_TEXTBOX&>(*mainGui.activeWindow->activeWidget).function();

Fail fast: throws std::bad_cast if you cast to the wrong type.

static_cast<GUI_TEXTBOX*>(mainGui.activeWindow->activeWidget)->function();

Run fast: Doesn't do a runtime check. So it won't fail fast. Rather, it will produce undefined behavior if you cast to the wrong type. Beware!

Johannes Schaub - litb