Fallen JLI MVP
Alter: 40 Anmeldedatum: 08.03.2003 Beiträge: 2860 Wohnort: Münster Medaillen: 1 (mehr...)
|
Verfasst am: 18.03.2009, 22:51 Titel: Interfaces/Guids für alle |
|
|
Einleitung:
Hier der Vorgänger auf dem dieser Artikel aufbaut:
http://www.jliforum.de/board/viewtopic.php?t=4800
Das Problem mit dem vorherigen Artikel war, dass dieser nur auf Microsofts VisualStudio/C++ ausgelegt war und daher nicht unter zB gcc kompiliert werden konnte und somit alles andere als portabel war.
Dieser Artikel soll dieses problem beseitigen indem zuerst Guids für alle zuer verfügung gestellt werden und gezeigt wird wie man Interfaces mit diesen verwenden kann.
Guids:
Guids sind eine 128Bit Datenstruktur welche es ermöglichen soll bestimmte Daten eindeutig zu kennzeichnen. korrekt erstellte Guids sind Weltweit eindeutig. Mehr Informationen dazu sind im passenden Wiki Artikel zu finden.
Ich stelle dies durch eine einfache Struktur dar:
CPP: | struct r_Guid
{
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[ 8 ];
bool operator==(const r_Guid& lr_Other) const
{
return (
((unsigned long *) this)[0] == ((unsigned long *) &lr_Other)[0] &&
((unsigned long *) this)[1] == ((unsigned long *) &lr_Other)[1] &&
((unsigned long *) this)[2] == ((unsigned long *) &lr_Other)[2] &&
((unsigned long *) this)[3] == ((unsigned long *) &lr_Other)[3]);
}
bool operator!=(const r_Guid& lr_Other) const
{
return !(*this == lr_Other);
}
}; |
Dies entspricht in etwa der Struktur welche von Microsoft verwendet wird nur die 2 Operatoren wurden hinzugefügt.
Da wir auf das __declspec Keyword verzichten müssen (MS only) sind wir in der Not einen Ersatz zu finden um unsere Interfaces mit den Guids auszustatten, unter MS ist dies sehr einfach:
CPP: | struct __declspec(novtable) __declspec(uuid("{EDFDE891-F04D-4061-8CCC-F95959C16354}")) iBaseObject |
Keine zusätze die wir erst includen müssen, oder aktivieren müssen. Nun wir müssen etwas mehr tun.
Als erstes erstellen wir uns 2 kleine Helfer, etwas das es uns ermöglicht das wir GUIDS an ein Interface binden können:
CPP: | template <typename T> struct UUID_Traits;
#define DEFINE_IID_TRAITS(a, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
template<> struct UUID_Traits<a>\
{\
static r_Guid GetIID()\
{\
const r_Guid lr_Guid = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } };\
return lr_Guid;\
}\
}; |
Wichtig für die spätere Verwendung ist dabei das Macro:
CPP: | #define DEFINE_IID_TRAITS(a, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) |
Schwer zu durchblicken aber hier die Erklärung:
Alles was das Macro benötigt ist der Name unseres Interfaces (Parameter 'a') und eine GUID (Parameter 'w1, w2, b1, b2, b3, b4, b5, b6, b7, b8'), die GUID kann man hier wieder aus einem GUID Generator bekommen. Leider sind die meisten GUIDS in dieser Form:
Zitat: | {B48C1F60-8C63-40fa-8B84-F274F3906664} |
Wir benötigen aber diese Form:
Zitat: | 0xb48c1f60, 0x8c63, 0x40fa, 0x8b, 0x84, 0xf2, 0x74, 0xf3, 0x90, 0x66, 0x64 |
Um das zu umgehen kann man sich entweder für r_Guid einen Kontruktor schreiben welcher einen String annimmt und diesen parst, oder man teilt die obere variante so auf das man die untere erhält. Wir nehmen vorerst die 2te Variante.
Interfaces:
Wir können nun bereits unser Interface mit einer GUID ausstatten:
CPP: | struct iTestInterface
: virtual iBaseObject // das gab es im vorherigen Artikel
{
virtual void TestMethod() = 0;
};
DEFINE_IID_TRAITS(iTestInterface,
0xb48c1f60, 0x8c63, 0x40fa, 0x8b, 0x84, 0xf2, 0x74, 0xf3, 0x90, 0x66, 0x64); |
Abstossend nicht wahr?
Eine Erleichterung könnte dies hier geben:
CPP: | #define interface(a, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
struct a; \
DEFINE_IID_TRAITS(a, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
struct a : virtual iBaseObject |
Dies macht im Grunde nichts anderes als das was wir getan haben nur etwas hübscher und es ist nicht mehr nötig unsere GUIDS nach dem Interface festzulegen durch die forward decleration unseres Interfaces:
CPP: | interface(iTestInterface, 0xb48c1f60, 0x8c63, 0x40fa, 0x8b, 0x84, 0xf2, 0x74, 0xf3, 0x90, 0x66, 0x64)
{
virtual void TestMethod() = 0;
}; |
Es sieht sogar etwas hübscher aus als die alte MS only Variante.
__uuidof(...) können wir nun auch nicht mehr verwenden doch dafür gibt es Abhilfe:
CPP: | template <typename T> inline r_Guid uuidof(T&)
{
return UUID_Traits<T>::GetIID();
}
template <typename T> inline r_Guid uuidof()
{
return UUID_Traits<T>::GetIID();
}
template <typename T> inline r_Guid uuidof(T*)
{
return UUID_Traits<T>::GetIID();
} |
Benutzt wird es zB in dieser Form:
CPP: | r_Guid lr_Guid = uuidof<iTestInterface>(); |
Der Nachteil ist das wir uuidof nur auf Interfaces anwenden können nicht auf die Implementierungen, da diese keine GUID zugewiesen bekommen haben, gebraucht wird dies allerdings sowieso nicht wenn man sich konsequent daran hält mit Interfaces zu arbeiten anstatt mit den tatsächlichen Implementierungen. _________________ "I have a Core2Quad at 3.2GHz, 4GB of RAM at 1066 and an Nvidia 8800 GTS 512 on Vista64 and this game runs like ass whereas everything else I own runs like melted butter over a smokin' hot 18 year old catholic schoolgirl's arse." |
|