1

这个问题也可以被命名为“如何在没有 ATL 的情况下进行引用计数”。这里这里已经提出了一些类似的问题,但在前者中回答了一个不同的问题,并且在这两种情况下都涉及 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()andRelease()实现,所以我写道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'

我错过了什么?

4

3 回答 3

1

这不需要更改接口定义:

template<class I>
class UnknownBase : public I
{
    ...
}

class Cat : public UnknownBase<IMammal>
{
    ...
}
于 2013-06-26T16:01:42.467 回答
0

您必须使用虚拟基类进行继承。改变:

IAnimal 类:公共 IUnknown --> IAnimal 类:公共虚拟 IUnknown;和

类 UnknownBase :公共 IUnknown --> 类 UnknownBase :公共虚拟 IUnknown

于 2013-06-26T03:53:41.663 回答
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();
};
于 2013-06-26T03:16:13.180 回答