An alternative to Forwarding Shims, but is it legal C++?
I recently came across the classic problem of needing to implement two
COM interfaces which happened to clash over a pair of methods with
identical names and signatures.
I read Essential COM years ago but forgot all about the Forwarding
Shims method of solving this problem. I'm going to use that for now
since it's standard and well understood.
Something else I tried has me curious, though. It seems like the
VS2005 C++ compiler lets you resolve the problem in the C# style. A
couple of things puzzle me, which is why I am posting to see what
other people thing.
First, let me show you a simple example. There's no COM involved here,
just straight C++:
#include <iostream>
using namespace std;
class ICowboy
{
public:
virtual const char *Draw() = 0;
};
class IArtist
{
public:
virtual const char *Draw() = 0;
};
class CAcePowel : public ICowboy, public IArtist
{
public:
CAcePowel() {}
~CAcePowel() {}
virtual const char *ICowboy::Draw() { return "Hands up,
sucker!"; } // LINE A
virtual const char *IArtist::Draw() { return "May I paint you,
sir?"; } // LINE B
};
int main(int argc, char* argv[])
{
CAcePowel *pAcePowel = new CAcePowel();
ICowboy *pCowboy = pAcePowel;
IArtist *pArtist = pAcePowel;
cout << "Cowboy: " << pCowboy->Draw() << endl; // LINE C
cout << "Artist: " << pArtist->Draw() << endl; // LINE D
delete pAcePowel;
return 0;
}
Now, according to a few things I have read (e.g. Chris Sells' page on
forwarding shims), LINE A and LINE B are not valid C++ and won't
compile. But with VS2005 they do compile. In fact, the example code
above seems to work perfectly. The program prints out:
Cowboy: Hands up, sucker!
Artist: May I paint you, sir?
** Question 1: ** Is what I have done in this example valid or does it
only work by accident?
Is is a feature nobody noticed before, or something that was added on
purpose in more recent versions of Visual Studio's C++ compiler?
Perhaps it's in there because the feature was required as part of C+
+.Net, to mimic the same behaviour (with slightly different syntax) as
in C#?
I think this is a more direct and cleaner way to solve the problem
than using forwarding shims but I don't want to use it in my code if
it is somehow risky or non-standard.
Another thing to note, briefly, is that the compiler protects against
any attempts to call pAcePowel->Draw() with an error saying the call
is ambiguous, which is good.
** Question 2: ** Assuming the above code is kosher, is it possible to
move the two Draw method bodies out of the class declaration?
To elaborate on this second question, replace the CAcePowel part of
the code with this:
class CAcePowel : public ICowboy, public IArtist
{
public:
CAcePowel() {}
~CAcePowel() {}
virtual const char *ICowboy::Draw();
virtual const char *IArtist::Draw();
};
If you build that in VS2005 then you get linker errors about two
symbols:
virtual char const * __thiscall CAcePowel[::ICowboy]::Draw(void)
virtual char const * __thiscall CAcePowel[::IArtist]::Draw(void)
That makes sense since the bodies of those two methods are not defined
anywhere... What I cannot work out is whether there is a valid syntax
for defining those methods, without the code ending up in the class
declaration.
I figure there may be some "using" trick, or a syntax with the scope
operator that I haven't thought of, to allow this but I've been unable
to get anything to work.
The fact that the linker seems to understand exactly what is going on
suggests that this feature is on VS2005 on purpose and that makes me
think there may be a syntax for defining these two function bodies
outside of the class. Does anyone know?
If anyone feels like messing around with this problem I've put a small
VS2005 project file here which will save you a couple of minutes
setting up a new project:
http://www.pretentiousname.com/temp/TwoFunsOneName.zip
(It's a combination of the two examples above.)
Many thanks for your time!