Я наткнулся на следующую проблему: у меня есть два пакета A и B, работающие нормально для каждого. У каждого свой интерфейс и своя реализация. Теперь я создал пакет C, объединяющий адаптер A с конкретной реализацией B. C фактически только реализует интерфейс A и пока только наследует и использует интерфейс B внутренне. В большинстве случаев этого было достаточно, чтобы иметь доступ только к интерфейсу A из контейнера, но теперь мне нужны также методы из B, доступные. Вот простой пример:
//----Package A----
class IA
{virtual void foo() = 0;};
// I cant add simply bar() here, it would make totally no sense here...
class A : public IA
{virtual void foo() {doBasicWork();} };
//----Package B----
class IB
{virtual void bar() = 0;};
class B1 : public IB
{
//Some special implementation
virtual void bar() {}
};
class B2 : public IB
{
//Some special implementation
virtual void bar() {}
};
// + several additional B classes , with each a different implementation of bar()
//---- Mixed Classes
class AB1 : public B1, public A
{
void foo() {A::foo(); B1::bar();}
};
class AB2 : public B2, public A
{
void foo() {A::foo(); B2::bar();}
};
// One Container to rule them all:
std::vector<IA*> aVec;
AB1 obj1;
AB2 obj2;
int main(){
iAvector.push_back(&obj1);
iAvector.push_back(&obj2);
for (std::vector<IA>::iterator it = aVec.begin(); it != aVec.end(); it++)
{
it->for(); // That one is okay, works fine so far, but i want also :
// it->bar(); // This one is not accessible because the interface IA
// doesnt know it.
}
return 0;
}
/* I thought about this solution: to inherit from IAB instead of A for the mixed
classes, but it doesnt compile,
stating "the following virtual functions are pure within AB1: virtual void IB::bar()"which is inherited through B1 though, and i cant figure out where to add the virtual
inheritence. Example:
class IAB : public A, public IB
{
// virtual void foo () = 0; // I actually dont need them to be declared here again,
// virtual void bar () = 0; // do i?
};
class AB1 : public B1, public IAB
{
void foo() {A::foo(); B1::bar();}
};
*/
Вопрос в том, как добиться комбинации обоих пакетов A и B, чтобы оба интерфейса были доступны из одного контейнера, а все детали реализации из A и B все еще наследуются?
Очевидное решение — создать комбинированный интерфейс:
class IAB : public virtual IA, public virtual IB
{
};
, иметь свой AB1
а также AB2
извлечь из этого (в дополнение к их
текущие выводы), и сохранить IAB*
в векторе.
Это означает, что B1
а также B2
должен также происходить практически из
IB
; учитывая направление, кажется, что дела идут, A
должен
вероятно, также получены практически из IA
,
Есть веские аргументы, что наследование интерфейса
всегда должен быть виртуальным. Не заходя так далеко: если класс
предназначен для получения из, а также у него есть основания, те основания
должно быть виртуальным (и, возможно, если класс не предназначен для
быть производным от вас, вы не должны получать от него). В твоем случае,
вы используете классическую технику миксина, и, как правило,
самое простое решение для всего наследования в миксине, чтобы быть
виртуальная.
Других решений пока нет …