Размышлял тут на тему интерфейов и возникли некоторые вопросы которые хотелось бы обсудить.
Есть проблема совместить иерархию интерфейсных классов с иерархией классов-реализаций. Для примера имеем:
// базовый класс для обьектов
struct Object {
virtual ~Object() {}
};
struct IA {
virtual void ia() = 0;
};
struct IB : IA {
virtual void ib() = 0;
};
// реализация IA
struct CA : Object, IA {
void ia() {}
};
// опс! это работать не будет IA входит в наследование дважды.
struct CB : CA, IB { // не работает
virtual void ib() {}
};
В этом примере есть класс Object который кажется лишним, но он нужен т.к. некоторые классы наследуются только от него не используя интерфейсы.
Чтобы решить проблему с классом СВ можно все интерфейсные классы наследовать виртуально:
struct IA {
virtual void ia() = 0;
};
struct CA : Object, virtual IA {
void ia() {}
};
struct IB : virtual IA {
virtual void ib() = 0;
};
struct CB : CA, virtual IB {
virtual void ib() {}
};
Так все работает, но есть небольшая заморочка. В такой схеме получается что у интерфейсов нет общего базового класса, а хотелось бы его иметь чтобы не иметь гемора с передачей параметров. Т.е. как вариант можно все интерфейсы наследовать виртуально от Object и классы тоже
struct IA : virtual Object {
};
struct MyClass : virtual Object, virtual IA { // реализация
};
Но с другой стороны Object и так будет входить в иерархию классов только один раз, как корень всех классов реализаций (в этом случае у интерфейсов нет общего базового класса). Но тут можно учесть то что интерфейс сам по себе жить не может и реализуется только в составе класса базового от Object и до Object можно всегда достучатся через dynamic_cast.
Вот с этого места я в раздумьях как поступить?
1. Наследовать все виртуально от Object?
2. Наследовать реализации невиртуально от Object, а у интерфейсов нет общего класса?
3. Наследовать реализации невиртуально от Object и завести общий класс для интерфейсов?
Есть такой подход:
class CObject
{
};
class IA
{
};
class IB : public IA
{
};
template <class T>
class IA_Impl : public T
{
// Реализация методов IA
};
class CA : public Object, IA_Impl<IA>
{
// Специфические для CA функции
};
class CB : public Object, IA_Impl<IB>
{
// Реализация только методов, добавленных в IB
// Специфические для CB функции
};
Если от IB тоже будут наследовать интерейсы, можно добавить IB_Impl
Не всегда это удобно, но зато позволяет собирать реализацию для интерфейсов по кусочкам
Здравствуйте, Left2, Вы писали:
L>Есть такой подход:
L>// поскипано
L>class CB : public Object, IA_Impl<IB>
L>{
L>};
L>
Такой хак я знаю, но давно от него отказался. В этом случае прийдется все классы держать в хидерах и любое изменение приводит к пересборке всего проекта, а это не есть гуд (в большом проекте).
Kluev wrote:
> Размышлял тут на тему интерфейов и возникли некоторые вопросы которые хотелось бы обсудить.
[]
http://www.rsdn.ru/Forum/?mid=517249Автор: Batiskaf
Дата: 24.01.04
--
Maxim Egorushkin
MetaCommunications Engineering
http://www.meta-comm.com/engineering/Posted via RSDN NNTP Server 1.8 beta