John Bandhauer wrote:
> I think it is better to detect instances of your object using
> QueryInterface rather than trust the cid. You can simply declare an iid
> locally in your implmentation and have the QI method respond with a
> pointer to your base object when QI'd for that iid. I think this is
> safer and has no more overhead than what you propose.
Ah, this really reduces the amount of involved code
to 4 lines (.. nsIClassInfo is out) - nice!
I'm still using the cid, but now the actual casting is done
in a custom QI impl :
NS_IMETHODIMP
btCBuffer::QueryInterface (REFNSIID aIID, void** aInstancePtr)
{
// ..
if ( aIID.Equals(this->GetCID()) ) {
*aInstancePtr = this;
return NS_OK;
}
// ..
Now I just QI to the CID and get back the right downcast.
void* _buf;
rv = otherBuffer->QueryInterface (this->GetCID(), &_buf);
// bail out: there's no btCBuffer behind !
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
// OK now, just a formal cast
btCBuffer* otherBuffer = static_cast<btCBuffer*>(_buf);
Thanks,
Tobias.
-------------------
details ..
class btCBuffer : public btIBuffer
{
public:
NS_DEFINE_STATIC_CID_ACCESSOR(BT_BUFFER_CID);
// ..snip
// NS_IMPL_ISUPPORTS1_CI(btCBuffer, btIBuffer);
NS_IMPL_ADDREF(btCBuffer)
NS_IMPL_RELEASE(btCBuffer)
// modified QI impl for safe ifc->component downcast
NS_INTERFACE_MAP_BEGIN(btCBuffer)
if ( aIID.Equals(this->GetCID()) ) {
*aInstancePtr = this;
return NS_OK;
}
NS_INTERFACE_MAP_ENTRY(btIBuffer)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, btIBuffer)
NS_IMPL_QUERY_CLASSINFO(btCBuffer)
NS_INTERFACE_MAP_END
NS_IMPL_CI_INTERFACE_GETTER1(btCBuffer, btIBuffer)
the above custom QI impl expands to:
NS_IMETHODIMP
btCBuffer::QueryInterface (REFNSIID aIID, void** aInstancePtr)
{
NS_ASSERTION(aInstancePtr,"QueryInterface requires a non-NULL
destination!");
if ( !aInstancePtr ) return NS_ERROR_NULL_POINTER;
nsISupports* foundInterface;
if ( aIID.Equals(this->GetCID()) ) {
*aInstancePtr = this;
return NS_OK;
}
if ( aIID.Equals(NS_GET_IID(btIBuffer)) )
foundInterface = NS_STATIC_CAST(btIBuffer*, this);
// .. snip