в примере я не нашел, как объявлен интерфейс IX. теоретически, он должен быть потомком IUnknown, который объявляется раньше других наследуемых классов (для построения vtable).
т.е., чтобы у тебя таблица была следующая:
vtable->
1. QI
2. AddRef
3. Release
4. ... прочие виртуальные методы
Так и есть:
//
// Iface.h
//
// Interfaces
interface IX : IUnknown
{
virtual void __stdcall Fx() = 0 ;
} ;
interface IY : IUnknown
{
virtual void __stdcall Fy() = 0 ;
} ;
interface IZ : IUnknown
{
virtual void __stdcall Fz() = 0 ;
} ;
// Forward references for GUIDs
extern "C"
{
extern const IID IID_IX ;
extern const IID IID_IY ;
extern const IID IID_IZ ;
extern const CLSID CLSID_Component1 ;
}
а так, здесь все норма. просто через reinterpret... ты получаешь указатель на свой vtable. что, мол, твой объект является экземпляром класса IUnknown и построен на базе его vtable. номером 2 (я считал с 1 ) в vtable интерфейса IUnknown стоит AddRef, а у тебя NondelegatingAddRef. ты просто пудришь мозги компилятору. проще говоря, он и вызывет метод 2 и попадает на NondelegatingAddRef.
Я проверил - reinterpret_cast <IUnknown*> (*ppv)->AddRef(); не изменяет адреса записанного в *ppv. Т.е он как бы говорит компилятору смотреть на указатель так, как будто бы он указывает на IUnknown. Выходит, что имена для компилятора не имеют значения - он производит вызовы по индексу в vtbl.
Но я не могу понять, почему в данном случае reinterpret_cast не изменил адрес указателя. В моём виденье должно быть так:
Объект CA:
____________
vtbl-> (фрагмент от IX)
0. QI();
1. AddRef();
2. Release();
3. Fx();
vtbl-> (фрагмент от InondelegatingUnknown)
0. InondelegatingQI();
1. InondelegatingAddRef();
2. InondelegatingRelease();
Фрагмент от CA
QI()
AddRef()
Release()
Fx()
InondelegatingQI();
InondelegatingAddRef();
InondelegatingRelease();
В дебагере я вижу что this = &InondelegatingUnknown - т.е их адреса совпадают... не понимаю почему так...
Теперь про reinterpret_cast <IUnknown*> (*ppv)->AddRef();
Я думал так (исходя из логики работы reinterpret_cast):
если указатель указывает на vtbl InondelegatingUnknown, то после
reinterpret_cast <IUnknown*> (*ppv) он будет содержать адрес IUnknown, но этого не происходит - почему?
Те же самые вопросы и по конструктору CA::CA(IUnknown* p);
CA::CA(IUnknown* pUnknownOuter) : m_cRef(1)
{
InterlockedIncrement(&g_cComponent);
if(pUnknownOuter == NULL)//если компонент не агрегируется
{
trace("Component no agrgation, use internal IUnknown");
m_pUnknownOuter = reinterpret_cast <IUnknown*>
(static_cast <INondelegatingUnknown*> (this));
INondelegatingUnknown* pX1 = static_cast <INondelegatingUnknown*> (this); //Здесь то же reinterpret_cast не изменяет адрес, выходит, что он просто заставляет трактовать данный указатель как IUnknown*, который на самом деле является INondelegatingUnknown*, а вызовы методов выполняются по индексу в vtbl. Это и есть полиморфизм :D Так я понял? Но почему в данном случае reinterpret_cast не изменяет адрес хоть убей не понимаю - неужели компилятор сам обо всём догадывается :?:
}
else
{
trace("Agrgation, delegating outer IUnknown");
m_pUnknownOuter = pUnknownOuter;
}
}