Как мне повторно использовать реализацию интерфейса во многих классах?

Этот вопрос также можно было бы озаглавить «Как вести подсчет ссылок без 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() а также 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'

Что мне не хватает?

1

Решение

Это не требует изменения определений интерфейса:

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

class Cat : public UnknownBase<IMammal>
{
...
}
1

Другие решения

Вы должны наследовать, используя виртуальные базовые классы. Изменить:

класс IAnimal: открытый IUnknown -> класс IAnimal: открытый виртуальный IUnknown; а также

класс UnknownBase: общедоступный IUnknown -> класс UnknownBase: общедоступный виртуальный IUnknown

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();
};
0
По вопросам рекламы [email protected]