Reputation: 12516
I am learning COM, also I am a beginner in C++. I defined three interfaces:
#include <objbase.h>
// pure abstract base class
interface IX : IUnknown{
virtual void __stdcall Fx() = 0; // pure virtual function
};
// pure abstract base class
interface IY : IUnknown{
virtual void __stdcall Fy() = 0; // pure virtual function
};
// pure abstract base class
interface IZ : IUnknown{
virtual void __stdcall Fz() = 0; // pure virtual function
};
extern "C"{
extern const IID IID_IX;
extern const IID IID_IY;
extern const IID IID_IZ;
}
Then I create a class with implementation of these interfaces:
#include <iostream>
#include "IFace.h"
// COM component
class CA :
public IX,
public IY,
public IZ
{
public:
CA();
~CA();
virtual void __stdcall Fx(); // IX
virtual void __stdcall Fy(); // IY
virtual void __stdcall Fz(); // IZ
// IUnknown (this interface implemented by IX, IY and IZ)
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
private:
// Each interface has own counter (for convenience of debugging)
ULONG ix_counter;
ULONG iy_counter;
ULONG iz_counter;
};
...
I want to use the separate counter of instances for each interface (for convenience of debugging). How I must define AddRef()
and Release()
function at this case?
I can do it such:
ULONG __stdcall CA::AddRef(){
// increase interface counter here
}
But this code is common for IX
, IY
and IZ
instances of my CA
class. If instance is IX
then I need increase the ix_counter
counter only. If instance is IY
then I need increase the iy_counter
counter only, etc.
I tried such approach:
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv); // common implementation
virtual ULONG __stdcall IX::AddRef(); // for IX instances
virtual ULONG __stdcall IX::Release(); // for IX instances
virtual ULONG __stdcall IY::AddRef(); // for IY instances
virtual ULONG __stdcall IY::Release(); // for IY instances
virtual ULONG __stdcall IZ::AddRef(); // for IZ instances
virtual ULONG __stdcall IZ::Release(); // for IZ instances
instead of
virtual ULONG __stdcall AddRef();
virtual ULONG __stdcall Release();
Also I tried:
// This is wrong definitions:
ULONG __stdcall CA::IX::AddRef(){
return InterlockedIncrement(&ix_counter);
}
ULONG __stdcall CA::IX::Release(){
InterlockedDecrement(&ix_counter);
ULONG count = ix_counter + iy_counter + iz_counter;
if (0 == count) delete this;
return count;
}
instead of
ULONG __stdcall CA::AddRef(){
// increase interface counter here
}
But my last replacement is wrong.
How can I define AddRef()
and Release()
functions individually for each interface?
Upvotes: 1
Views: 198
Reputation: 69724
You can have a counter specific to interface. Your code could look like this:
// (interfaces defined)
template <typename T, typename Base>
class CUnknownWithCounterT :
public Base
{
public:
ULONG m_nCounter;
public:
CUnknownWithCounterT() :
m_nCounter(0)
{
}
ULONG __stdcall AddRef()
{
m_nCounter++;
return static_cast<T*>(this)->InternalAddRef();
}
ULONG __stdcall Release()
{
m_nCounter--;
return static_cast<T*>(this)->InternalRelease();
}
};
class CA :
public CUnknownWithCounterT<CA, IX>,
public CUnknownWithCounterT<CA, IY>,
public CUnknownWithCounterT<CA, IZ>
{
public:
ULONG m_nMainCounter;
public:
// QueryInterface as stuff...
ULONG __stdcall InternalAddRef()
{
return ++m_nMainCounter;
}
ULONG __stdcall InternalRelease()
{
return --m_nMainCounter;
}
};
Ready to go:
CA A;
IX* pX = &A;
IY* pY = &A;
IZ* pZ = &A;
pY->AddRef();
pZ->AddRef();
pZ->AddRef();
_tprintf(_T("%d %d %d\n"),
A.CUnknownWithCounterT<CA, IX>::m_nCounter,
A.CUnknownWithCounterT<CA, IY>::m_nCounter,
A.CUnknownWithCounterT<CA, IZ>::m_nCounter,
0);
// 0 1 2
However you need to also override QueryInterface respectively because it also returns a pointer in the way that respective counter needs an increment.
The implementation will be COM compliant (m_nMainCounter
is having that counter for COM), the question is whether individual counters are accurate in helping you find reference leaks. If they are helpful most of the time, then you certainly have them useful for troubleshooting.
Upvotes: 1
Reputation: 170539
I want to use the separate counter of instances for each interface (for convenience of debugging). How I must define AddRef() and Release() function at this case?
This is totally in violation of COM rules. One of the requirements is that whenever you retrieve IUnknown*
through any pointer of any type that points to a specific object you get the same pointer value. This is why you simply cannot have a separate counter in any meaningful way.
Upvotes: 1
Reputation: 948
I think you should inherit the common implementation from a class implementing IUnknown. That would parallel what COM defines.
Upvotes: 0