简体   繁体   中英

What am I doing wrong with this pointer cast?

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 :)

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

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<>().

You just need more parentheses:

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

Actually, this would work too:

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

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.

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();

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!

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

-> 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM