The kind of problem that makes the best of us resort to late-night refrigerator-punchings [grin]
Say you have a simple data type that is platform-specific, e.g.
COLORREF
There is no way to express this data type as null, because 0 is just as valid as 0xFFFFFFFF (-1) for it.
Our base class object (call it an EditControl) is the interface for all EditControl implementations (Win32, *nix, Mac, etc...). When creating an "EditControl", we use an inner struct EditControl::style, which is a POD that contains style type pointers, and such. One of those should be the background color for the EditControl's implementation.
Since we can't express COLORREF as a null or non-existent member, we need to wrap it in a class... and then pass a pointer (of that class) to the EditControl::style for background "Color"... if the default parameter = 0, meaning the pointer to "Color" is zero, we can set an EditControl::style with no default background "Color" member... groovy.
Now, lets pretend we need this simple data type (COLORREF) when wrapping some C-based api, namely ::SetBkColor(hdc,color)...
We can't extract COLORREF from EditControl::style's "backgroundcolor" member, because EditControl::style lives at the base-class level (EditControl), not the implementation level (Win32EditControl)...
What does that mean? It means that EditControl::style doesn't know "COLORREF", nor can it return "COLORREF" to us.
----------------------
Now you're all thinking... hmmm... template-ize that mother.
//inside class Edit control...
template<typename ImplementationType>
struct style{
public
ImplementationType backgroundcolor() { return backgroundcolor; }
private:
ImplementationType backgroundcolor;
};
// later, somewhere else...
style<COLORREF> bgcolor;
That's fine; but here's the complication...
...we need to be able to pass these "style" structs around in pointers, preferrably smart pointers... why? So they get deleted when no longer referenced, for starters...
// inside EditControl class...
EditControl(style_ptr_type s); // constructor prototype
typedef Loki::SmartPtr<style> style_ptr_type; // a HA! Doesn't work!!
That doesn't work... because we don't know the template parameter of style yet; it's not a "real" type.
So, if we want to templatize "EditControl::style", we can't know its type, and thus can't pass it into the EditControl constructor... which means the style struct is useless to us!
----
Template specialization is not really a help, either...
//inside a "Color" class
template<class DerivedType, class ImpType>
ImpType type(DerivedType &d);
// Color is declared a friend of it's derived type, Win32Color...
// specialization
template<>
COLORREF Color::type(Win32Color &c)
{
return c._bgcolorref;
}
That would be OK... IIIIIF... EditControl::style had pointers to Win32Color, instead of pointers to Color...
This ugly hack is out of the question!!
// ay ay ay!!!
_pstyle->_pColor->type(*(static_cast<Win32Color *>(GetImpl(_pstyle->_pColor))));
----------------------
What this code has done is basically left me numb [smile]... and wanting a different approach...
How common is this design problem in OOP?
This may be a crazy design; but I'd like something that kept the abstraction layer (Base class) and implementation layer (Concrete class) separate... I don't want to identify "COLORREF" as the value inside a "Color" class... but need to get a "COLORREF" somehow so the Win32 APIs will be available.
I have to step back and let the world swirl by for a while...
later...
and thanks
[imwithstupid]
[Edited by - Verg on July 28, 2005 12:57:32 PM]