Casting up to a derived class [solved]

Started by
17 comments, last by Valor Knight 17 years, 5 months ago
This is my situation: Class A Class B : public A function( A &input ) { //I need to cast input (currently A) to a B class } I need to cast the input from a base class to the required class. Why I need to do this is because I have a component or something that has functions I need to access outside of the base class. The current situation is I have a window class and a MSWindow class. As I dont know if linux, ect uses HWND, I have a class derived from window, MSWindow, which has a GetHWND() function. I will also need to use this later on in a component manager. I know static_cast<> can cast down B to A. dynamic_cast<> can cast up (I think) But I was told never to use dynamic casting in a game. How can I cast my input to the correct class? Also is HWND used for linux/mac as well? trying for api independence and dont want a base class with a MS only handle. [Edited by - Valor Knight on October 22, 2006 6:59:09 PM]
There is no life without honor
Advertisement
Quote:Original post by Valor Knight
I know static_cast<> can cast down B to A. dynamic_cast<> can cast up (I think) But I was told never to use dynamic casting in a game. How can I cast my input to the correct class?


dynamic_cast is perfectly fine in games too.

Quote:Original post by Valor Knight
Also is HWND used for linux/mac as well? trying for api independence and dont want a base class with a MS only handle.


No HWND is not used on those platforms. If you want a platform independent windowing API for all the three platforms you mentioned, I can recommend wxWidgets: http://www.wxwidgets.org.

If you are 100% absolutely undoubtedly sure that you do have an object of type B, then you can use static_cast<B&>(input). If you can't guarantee that, use dynamic_cast<B&>(input), which will throw an std::bad_cast exception if you really didn't have a B (or derived). When casting pointers (i.e. dynamic_cast<B*>(&input)), you instead get a null pointer if the cast fails.

Quote:But I was told never to use dynamic casting in a game.


That's bullshit. There is nothing else you can use here. The tools are there, use them when you need them, otherwise you'll waste time coming up with a solution that's likely to both be slower and less maintainable.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
HWND is windows only. But it's just a typedef'd type, like a DWORD is an unsigned long. You can make your variable of the base type and be ok as long as the other OS's use the same or smaller sized types for their IDs.

Or, wrap the code in #ifdef's/#endif's or other solutions mentioned on this site by others (I do the #ifdef way, personally like it better then other solutions I've seen so far).
Quote:Original post by Fruny
Quote:But I was told never to use dynamic casting in a game.


That's bullshit. There is nothing else you can use here. The tools are there, use them when you need them, otherwise you'll waste time coming up with a solution that's likely to both be slower and less maintainable.


I'll mantain that a virtual functions are usable - and often more mantainable - "here" (where here is the problem you're trying to solve using upcasting). That said, there are situations where dynamic_cast is the superior solution, and it is definately usable in game code.

Use it the wrong way, and yes, your performance will tank. For example, you don't want to try and dynamic_cast individual pixels in a screen buffer array. That said, 99.999% of C++, if used the wrong way, will simply invoke undefined behavior and crash in a messy, hard to track down or predict way, so this is really more of a benifit to dynamic_cast<>s than anything else.



In this case, it smells a bit like design rot. On linux, the system should never get an MSWindow. On windows, the system should never not get one. As such, I'd expect this kind of thing to be checked and verified at compile time, not run time. Just a thought.

[Edited by - MaulingMonkey on October 21, 2006 8:39:39 PM]
This is exactly one of the very few situations I've needed to use dynamic_cast, and it's perfectly fine as long as you know why you are using it. It can hint at a bad design, but I use it to get the HWND when I'm setting up DirectX.
When creating platform-dependant classes I tend to take a different approach and not use inheritence at all. In your case if you have a class called PlatformWindow and derived classes MSPlatformWindow and LinuxPlatformWindow, what I do instead is this...

//------------------// PlatformWindow.hstruct PlatformWindowHandle;class PlatformWindow{public:    const PlatformWindowHandle& GetHandle() const { return *m_handle; }private:    std::auto_ptr<PlatformWindowHandle> m_handle;}//------------------// Win32Impl.hstruct PlatformWindowHandle{    HWND hWnd;};//------------------// LinuxImpl.hstruct PlatformWindowHandle{    int handle;};


You do something similar for each of your platform-dependant classes, and then have a single header that defines the various platform-dependant structs such as PlatformWindowHandle that contain your HWND. The important part here is that the PlatformWindowHandle type is not defined in the PlatformWindow header, and you only deal with pointers & references to it. This allows you to hide the platform-specific details while still providing access to platform-specific data, without having to rely on pointless inheritence (since you need to recompile for each platform, the desired platform-specific class is known at compile-time).
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
@joanusdmentia:
That's a really good idea. Then just #ifdef around the headers you need.
Thanks for the info on dynamic_cast. I will ignore what that person said about it. Thanks for the input


As for the HWND: I should have thought of this earlier but I just came up with. I dont know what I was thinking about the dervied classes (when I wrote it, it looked stupid to me):

#ifdef WIN32
typedef HWND WinHandle;
#endif

classWindow
{
WinHandle GetWindowHandle();
};
There is no life without honor
There's also the question of why external code should ever need access to the HWND. In most cases, only member functions should need to use it.

[Edited by - Fruny on October 21, 2006 10:49:20 PM]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan

This topic is closed to new replies.

Advertisement