Stingray® Foundation : Chapter 3 Interface‑Based Programming : IQueryGuid and guid_cast
IQueryGuid and guid_cast
One way to create functionality similar to QueryInterface() is to use the C++ dynamic_cast() operator. This is an effective solution if your compiler supports it. Enabling RTTI also introduces some extra overhead for every class compiled. Many developers prefer to avoid enabling RTTI, or at least want a choice in the matter. The solution used by SFL avoids the use of C++ RTTI by introducing an interface that provides a function very similar to IUnknown’s QueryInterface(). The IQueryGuid interface has a single method, QueryGuid() which allows the caller to pass in a GUID and get back a pointer to an interface or class. It is exactly like QueryInterface(), except that QueryGuid() is more generic. QueryInterface() is only meant to get back pointers to interfaces. QueryGuid() acts as a substitute for dynamic_cast, so it is perfectly acceptable to associate a GUID with a concrete class and then use QueryGuid() to cast pointers to that concrete class. Example 1 shows how IQueryGuid is defined.
Example 1 – Defining IQueryGuid
class IQueryGuid
{
public:
virtual bool QueryGuid(REFGUID guid,void **ppvObj)=0;
};
QueryGuid() is similar to QueryInterface() with a couple of notable exceptions. First, QueryGuid() returns TRUE if the interface is supported by the object and FALSE if it fails. The most important difference is that QueryGuid() does not make any assumptions about reference counting. Although QueryInterface() always increments the reference count on an interface before returning it to the caller, QueryGuid() does not. This is because IQueryGuid does not have any reference counting methods. It is perfectly valid to use IQueryGuid for casting interfaces and classes that do not support reference counting.
Example 2 shows a class that implements IQueryGuid.
Example 2 – Implementing IQueryGuid
class __declspec(uuid("81CEDD2C-B2F0-4702-AA2F-D912497F5F33"))
IAnimal : public IQueryGuid
{
public:
virtual void Eat() = 0;
virtual void Sleep() = 0;
virtual void Reproduce() = 0;
};
 
class CCow : public IAnimal
{
public:
virtual bool QueryGuid(REFGUID guid,void **ppvObj)
{
*ppvObj = NULL;
if (guid == __uuidof(IAnimal))
*ppvObj = static_cast<IAnimal*>(this);
else if (guid == __uuidof(IQueryGuid))
*ppvObj = static_cast<IQueryGuid*>(this);
return (*ppvObj != NULL);
}
virtual void Eat()
{
// chew some grass
}
virtual void Sleep()
{
// sleep standing up?
}
virtual void Reproduce()
{
// not a pretty sight
}
};
NOTE >> Notice that declspec uuid is used to associate a GUID with the IAnimal interface. The __uuidof operator can then be used to return the GUID for IAnimal in the implementation of QueryGuid().
The guid_cast template function makes QueryGuid() type safe, so it is more like dynamic_cast and easier to use. It acts like dynamic_cast and is implemented by calling QueryGuid(). Example 3 shows how guid_cast is used.
Example 3 – Using the guid_cast template function
void MakeAnimalEat(IQueryGuid* pObj)
{
IAnimal* pAnimal = guid_cast<IAnimal*>(pObj);
if (pAnimal)
pAnimal->Eat();
}