Bear with me as I dump the following simplified code: (I will describe the problem below.)
class CMyClass
{
...
private:
HRESULT ReadAlpha(PROPVARIANT* pPropVariant, SomeLib::Base *b);
HRESULT ReadBeta(PROPVARIANT* pPropVariant, SomeLib::Base *b);
typedef HRESULT (CMyClass::*ReadSignature)(PROPVARIANT* pPropVariant, SomeLib::Base *b);
HRESULT TryFormats(ReadSignature ReadFormat, PROPVARIANT* pPropVariant);
};
inline HRESULT CMyClass::ReadAlpha(PROPVARIANT* pPropVariant, SomeLib::Base *b)
{
if (b)
{
// got a valid Base. Handle generic stuff here.
SetStuff(pPropVariant, b->someInt);
return S_OK;
}
return (b != NULL) ? 0 : -1;
}
inline HRESULT CMyClass::ReadBeta(PROPVARIANT* pPropVariant, SomeLib::Base *b)
{
if (b)
{
SomeLib::FormatA *fa;
SomeLib::FormatB *fb;
if ( fa = dynamic_cast<SomeLib::FormatA*>( b ) )
{
// specific code for FormatA
SetStuff(pPropVariant, fa->getVersion());
return S_OK;
}
else if ( fb = dynamic_cast<SomeLib::FormatB*>( b ) )
{
// specific code for FormatB
SetStuff(pPropVariant, fb->valueForB);
return S_OK;
}
}
return (b != NULL) ? 0 : -1;
}
inline HRESULT CMyClass::TryFormats(ReadSignature ReadFormat, PROPVARIANT* pPropVariant)
{
HRESULT hr;
if (FAILED(hr = (this->*ReadFormat)(pPropVariant, _pFile->formatA())))
if (FAILED(hr = (this->*ReadFormat)(pPropVariant, _pFile->formatC())))
hr = (this->*ReadFormat)(pPropVariant, _pFile->formatD());
return hr;
}
I end up calling this code like:
hr = TryFormats(&CMyClass::ReadAlpha, pPropVar);
Now... the problem is that this is too generic and constrained, especially now that I am trying to refactor this code for use in some other projects. So, this means that I want to place the ReadXxx
code in another source file and abuse templating somehow. The TryFormats
remains in the class since different classes have different formats they attempt to read.
My current approach is bound to fail due to the dynamic_cast<Derived*>
needed for functionality that is not in the Base
class, and since I may need to read up to 5 different formats in one class, I really don't want to drag in formats I do not need in the first place. (For example, see above how CMyClass
does not support SomeLib::FormatB
, yet the ReadBeta()
needs to support it and thus forces the compiler to compile all the relevant information in.) In total, I have around 10 different formats I 'support' like this.
How can I properly refactor this code? I don't want to need to rewrite Base
functionality for every descendant, nor do I want to put derived specific information into a function that simply takes a Base
.
I have tried some things, but all I manage to squeeze out of my compiler are rainbows of errors. Rather than confuse the people here with my attempts, I figured I'd give my (simplified) original working code and allow the experts to draw their own conclusions on how to do this. In reality, there's about 50 of those ReadXxx
functions, but they either follow the general structure of the ReadAlpha
or ReadBeta
functions above. So if someone can show me how to do those, I can without an issue convert my actual code. (I imagine I will need to change TryFormats()
definition as well, and that's no problem either - I am just hoping someone can show me how to do get the above example refactored properly.)
Thank you, and my apologies for the long, long question.