这个问题也可能被称为“如何在没有ATL的情况下进行参考计数”。有人提出了类似的问题here和here,但前者提出了一个不同的问题,在这两种情况下都涉及ATL。我的问题对于C ++更为通用,而不是关于COM。
假设我们有一个IUnknown
“界面”,如下所示:
class IUnknown
{
public:
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
virtual ULONG QueryInterface(void * iid, void **ppv) = 0;
};
...让我们抛出一些虚构SDK中的其他接口:
class IAnimal : public IUnknown
{
public:
virtual IAnimal** GetParents() = 0;
};
class IMammal : public IAnimal
{
public:
virtual ULONG Reproduce() = 0;
};
由于我将要实施几种动物和哺乳动物,我宁愿不复制粘贴每个类中的AddRef()
和Release()
实现,所以我写了UnknownBase
:
class UnknownBase : public IUnknown
{
public:
UnknownBase()
{
_referenceCount = 0;
}
ULONG AddRef()
{
return ++_referenceCount;
}
ULONG Release()
{
ULONG result = --_referenceCount;
if (result == 0)
{
delete this;
}
return result;
}
private:
ULONG _referenceCount;
};
...以便我可以使用它来实现Cat
:
class Cat : public IMammal, UnknownBase
{
public:
ULONG QueryInterface(void *, void**);
IAnimal** GetParents();
ULONG Reproduce();
};
ULONG Cat::QueryInterface(void * iid, void **ppv)
{
// TODO: implement
return E_NOTIMPL;
}
IAnimal** Cat::GetParents()
{
// TODO: implement
return NULL;
}
ULONG Cat::Reproduce()
{
// TODO: implement
return 0;
}
...但是,编译器不同意:
c:\path\to\farm.cpp(42): error C2259: 'Cat' : cannot instantiate abstract class
due to following members:
'ULONG IUnknown::AddRef(void)' : is abstract
c:\path\to\iunknown.h(8) : see declaration of 'IUnknown::AddRef'
'ULONG IUnknown::Release(void)' : is abstract
c:\path\to\iunknown.h(9) : see declaration of 'IUnknown::Release'
我错过了什么?
答案 0 :(得分:1)
这不需要更改接口定义:
template<class I>
class UnknownBase : public I
{
...
}
class Cat : public UnknownBase<IMammal>
{
...
}
答案 1 :(得分:0)
您可以使用允许您将基类指定为模板参数的类模板。这将消除在派生类中实现最终覆盖函数的需要。
您还需要确保使用正确的调用约定,返回类型和参数类型声明成员函数。
template<typename Base>
class UnknownImpl : public Base
{
public:
UnknownImpl() : _referenceCount(0)
{
}
ULONG STDMETHODCALLTYPE AddRef()
{
return InterlockedIncrement(&_referenceCount);
}
ULONG STDMETHODCALLTYPE Release()
{
ULONG result = InterlockedDecrement(&_referenceCount);
if (result == 0)
{
delete this;
}
return result;
}
private:
ULONG _referenceCount;
};
class Cat : public UnknownImpl<IMammal>
{
public:
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**);
IAnimal** GetParents();
ULONG Reproduce();
};
答案 2 :(得分:0)
您必须使用virtual base classes继承。变化:
class IAnimal:public IUnknown - &gt; class IAnimal:public virtual IUnknown;和
class UnknownBase:public IUnknown - &gt; class UnknownBase:public virtual IUnknown