Sign in to follow this  

Accessing Interface Class Specifics in Rare Circumstances

This topic is 4728 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've already done some searching for the answers to my problem and have discovered what seems like the best fix. Basically, I just want some clever people to look it over and either a) tell me whether it would work or b) suggest a better alternative. The Scenario Imagine a cApplication class has two member variables: m_Platform and m_Renderer. These member variables are pointers to interface classes (IPlatform and IRenderer, respectively). This is done for platform/API independence and means that each class will have a set of generic cross-platform/API functions. Each of these interface base classes will have a number of concrete classes derived from them. Now, the concrete platform classes should be able to stand alone but the Renderer classes may need access to platform-specific info (e.g. the DirectX API needs window handles at init time). How can I provide access to platform specifics through a pointer to the generic base class? I have seen one way of doing this where the platform interface class has an enumeration such as:
enum PlatformID { PLATFORM_WIN, PLATFORM_MAC, PLATFORM_LIN }; 
The interface has a function like:
virtual PlatformID GetID() = 0;
And then each derived, concrete class provides an implementation of the function that returns its own ID (i.e. the Windows version would return the ID PLATFORM_WIN). The renderer would then query the platform ID, cast the platform base class pointer to a specific type and then call a set of platform specific methods. The main drawback I can see is that the addition of a new platform would mean an addition to the interface enumeration and therefore require everything to be recompiled. Is there a better way for interface classes to provide access to derived class specifics? [Edited by - pan narrans on January 1, 2005 10:15:05 AM]

Share this post


Link to post
Share on other sites
Does the platform change at runtime? Probably not. In this case the virtual functions are largely unnecessary.

Use a few generic programming techniques, such as template traits classes or namespace aliasing for type-safety:

namespace Platforms
{
namespace Windows
{
typedef HWND Window;
}

namespace Linux
{
typedef void* Window;
}

}

#ifdef _WIN32
namespace Platform = Platforms::Windows;
#elif
// etc.



Unfortunately I think you may find that each platform has slightly different abstractions, making this endeavor difficult.

Share this post


Link to post
Share on other sites
Sorry, the example I've used is obviously flawed. Just imagine that it isn't a platform class, they are just two interface classes that need to pass specific data to one another. Should I use the method above, or mess about with void pointers?

Share this post


Link to post
Share on other sites
You have to hide all the details of a platform and, since you will not to use different platforms at the same time, you can use different settings for your project:

if you want to compile for Linux you'll use:
IPlatform.h
PlatformLinux.h (derived from IPlatform)
PlatformLinux.cpp

if you want to compile for Windows you'll use:
IPlatform.h
PlatformWindows.h (derived from IPlatform)
PlatformWindows.cpp

You'd better don't use ID at all (in this solution you don't need them).
To take advantage of something platform specific you have to hide the concept that varies in another class.
For example if Linux refers to a window using "void *" instead Windows uses "HANDLE", you'll solve your problem using IWindow and deriving form it IWindowForLinux, IWindowForWindows. When you have to move a window you'll have:


class IWindow
{
virtual void MoveTo(int x, int y)
{
// pPlatform point to the current platform (maybe a singleton)
pPlatform->MoveTo(x,y,this);
}
}

class IWindowForLinux : public IWindow
{
void * m_pWnd;
}

class IWindowForWindow : IWindow
{
HANDLE m_hWnd;
}

[in platformwindows.cpp]
void IPlatformWindow::MoveTo(IWindow * pWnd, int x, int y)
{
IWindowForWindows * p=(IWindowsForWindows*)pWnd;
SetWindowPos(p->m_hWnd, x, y, ...other arguments...);
}

[in platformlinux.cpp]
void IPlatformLinux::MoveTo(IWindow * pWnd, int x, int y)
IWindowForLinux * p = (IWindowForLinux*)pWnd;
XWindowSetPos(x,y,p->m_pWnd, ... other arguments...); // <- invented
}

char * title="My window";
IWindow * pWindow=pPlatform->CreateNewWindow(title);
pWindow->MoveTo(x,y);




As you can see there is no "void *" neither "HANDLE": they're hidden by child classes.

Hope that helps.

Share this post


Link to post
Share on other sites
Thanks, but I know how to use interface classes to hide the specific details of concrete classes. My question is about those few times when these specifics might need to be known elsewhere (yeah, in a perfect world it shouldn't happen) but it seems I'm unable to express the question clearly enough. FOR EXAMPLE: a Platform interface (of any kind) would wrap the windows HANDLE so that it can't be seen by any other class; however, some other classes may need access to it in rare circumstances (i.e. a totally seperate Renderer interface might need that window HANDLE for one of its implementations in order to initialise).

Perhaps looking at this might help someone understand (particularly the post by MRom). Anyway, looks like I'll have to do it the way I said, and see if I run into any problems.

Share this post


Link to post
Share on other sites
Quote:
Original post by antareus
Why can't you use namespace aliasing for the types?

I could for the example I gave originally, but I was thinking in more general terms (e.g. where one implementation may even provide functions that another can't). My solution must be way off, nevermind, thanks a lot anyway.

Share this post


Link to post
Share on other sites
Why not just skip the type identifier and use the language's type information facilities? In C++ just dynamic_cast and be done with it.

Share this post


Link to post
Share on other sites

This topic is 4728 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this