Re: stroustrup, void*, and reinterpret_cast
Dilip wrote:
In MSFT's COM-land, there is an API called CoCreateInstance -- its last
parameter is of type void**. This API is used to get a pointer to the
interface (abstract class to be precise) you are interested in. So
people always do something like this:
struct IUnknown
{
virtual void QueryInterface(REFIID riid, void** ppv) = 0;
virtual void AddRef() = 0;
virtual void Release() = 0;
};
struct ISomeInterface : public IUnknown
{
virtual void DoIt() = 0;
};
ISomeInterface* isi;
CoCreateInstance(......,...., reinterpret_cast<void**>(&isi));
Internally a lot of hocus-pocus happens and the API ends up calling an
implementation of a standard IUnknown method called QueryInterface that
returns a pointer to ISomeInterface like so:
class SomeInterfaceImpl : public ISomeInterface
{
void QueryInterface(REFIID riid, void** ppv)
{
*ppv = static_cast<ISomeInterface*>(this);
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
}
// remaining implementations elided for clarity
};
Have the proper casts been used in the above code? Can you explain why
reinterpret_cast is needed in places where its been used?
This is pretty system specific, so I don't know if this will go or not.
But, I think I can explain that. A COM object can implement many
independent interfaces as well as inherited interfaces and All
interfaces inherit from IUnknown. So, they end up constructing a
fairly fancy vtbl to implement all of this. The static_cast<> above
can move the pointer up and down the vtbl to the root of the
appropriate interface. The reinterpret_cast<> is then used to be sure
that the appropriate IUnknown will be invoked without further moving of
the pointer. I will try to draw a picture. If we have 2 interfaces,
we might have a vtbl that looks like this:
1: IUnknown
2: IInterface1
3: IUnknown
4: IInterface2
if we static cast to Interface2, the pointer will correspond to
position 3. When we invoke the IUnknown addref method, we want the
IUnknown from position 3 and not the IUnknown and position 1. To
indicate that there is something tricky going on and that we are
getting a specific IUnknown, they are using a reinterpret_cast.
Hopefully that sheds some light and isn't too far off base.
To bring it back to normal C++, we can imagine an interface like:
class base
{
virtual ~Base(){}
virtual void Print() = 0;
}
class IInterface1 : public Base
{
}
class IInterface2 : public Base
{
}
class Implement : public IInterface1, public IInterface2
{
}
Now, if we wanted to get a pointer to the Base that came with
IInterface2 we might static_cast to IInterface2 the reinterpret cast to
Base. I do not believe that the reinterpret_cast is required to do
this, but it does signal that something tricky is going on.
Hopefully, I haven't spread too many lies above, I have slept at least
once since doing any COM stuff. :)
joe
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]