Accessing Interface Class Specifics in Rare Circumstances

Started by
7 comments, last by SiCrane 19 years, 4 months ago
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]
Minister of Propaganda : leighstringer.com : Nobody likes the man who brings bad news - Sophocles (496 BC - 406 BC), Antigone
Advertisement
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 _WIN32namespace Platform = Platforms::Windows;#elif// etc.


Unfortunately I think you may find that each platform has slightly different abstractions, making this endeavor difficult.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
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?
Minister of Propaganda : leighstringer.com : Nobody likes the man who brings bad news - Sophocles (496 BC - 406 BC), Antigone
That's too little information to give you decent advice. If you need to know derived class specifics then your base class may need refactoring.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
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.
Fil (il genio)
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.
Minister of Propaganda : leighstringer.com : Nobody likes the man who brings bad news - Sophocles (496 BC - 406 BC), Antigone
Why can't you use namespace aliasing for the types?
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
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.
Minister of Propaganda : leighstringer.com : Nobody likes the man who brings bad news - Sophocles (496 BC - 406 BC), Antigone
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.

This topic is closed to new replies.

Advertisement