2010-06-13 13 views
5

Sto cercando di capire this example code in merito a Browser Helper Objects.Come funziona l'implementazione di più interfacce COM in C++?

All'interno, l'autore implementa una singola classe che espone più interfacce (IObjectWithSite, IDispatch).

La sua funzione QueryInterface esegue le seguenti:

if(riid == IID_IUnknown) *ppv = static_cast<BHO*>(this); 
else if(riid == IID_IObjectWithSite) *ppv = static_cast<IObjectWithSite*>(this); 
else if (riid == IID_IDispatch) *ppv = static_cast<IDispatch*>(this); 

Ho imparato che da un punto di vista C, i puntatori di interfaccia sono solo dei rimandi a VTables. Quindi penso che C++ sia in grado di restituire il VTable di qualsiasi interfaccia implementata usando static_cast.

Ciò significa che una classe costruita in questo modo dispone di una serie di VTables in memoria (IObjectWithSite, IDispatch, ecc.)? Cosa fa C++ con il nome collisioni sulle diverse interfacce (ognuna ha una funzione QueryInterface, AddRef e Release), posso implementare metodi diversi per ognuna di queste?

risposta

6

Sì, ci sono più tabelle v, una per ogni interfaccia ereditata. Il static_cast < lo restituisce. Il compilatore si assicura che i metodi comuni nelle interfacce ereditate siano condivisi, riempie ogni slot v-table con un puntatore alla stessa funzione. Quindi hai solo bisogno di un'implementazione di AddRef, Release, QueryInterface. Proprio quello che vuoi Niente di tutto ciò è un incidente.

Questo è sempre un problema quando una coclasse implementa più interfacce con lo stesso metodo che non si desidera dare la stessa implementazione. Il metodo IConnectionPoint :: Advise() è un esempio famoso. O era DAdvise()? Sfortunatamente, non ricordo con che cosa si è scontrato e come è stato risolto, è stato coperto da ATL Internals. Ottimo libro btw.

+1

Grazie! Ho fatto qualche lettura personale e ho scoperto che non solo crea VTables diversi, ma crea anche funzioni "thunk" per correggere il puntatore prima di reindirizzare alla funzione comune. – Martin

3

In ereditarietà multipla, più VTables sono disposti in sequenza come seguente formato se dato this puntatore (che indicano primo byte, 01)

[01] [02] [03] [04] [05] [ 06] [07] [08] [09] [10] [11] [12]
[Ptr di VTableA] [Ptr di VTableB] [Ptr di VTableC]

In C++, solo 1 attuazione sarà generato prototipo per funzione in più scenari di interfaccia. Tuttavia, per lo scenario di ereditarietà normale, la superclasse potrebbe avere un'implementazione predefinita ei bambini che eseguono l'override della funzione avranno i VTables che puntano a contenuti diversi rispetto al genitore.