Георгий |
Отправлено: 20.10.2004, 22:05 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
CODE | #include <iostream.h>
class base
{
public:
int a;
virtual void M(void){cout<<"asd"<<endl;};
};
class ParentA:virtual public base
{
public:
void M(void){cout<<"dfg"<<endl;};
};
class ParentB:virtual public base
{
public:
void M(void){cout<<"qwe"<<endl;};
};
class Child:virtual public ParentA, virtual public ParentB{};
class Child2:virtual public ParentA, virtual public base{};
class Child3:virtual public ParentB, virtual public base{};
class Child4:virtual public base, virtual public ParentB{};
class Child5: virtual public base, virtual public ParentA{};
void main(void)
{
Child c;
Child2 c2;
Child3 c3;
Child4 c4;
Child5 c5;
base *v[]={&c2,&c3,&c4,&c5};
//c.M();
const int len = sizeof(v) / sizeof(v[0]);
for(int i=0;i<len;++i)
v[i]->M();
}; |
класс base предоставляет абстрактный интерфейс для неких действий;
ParentA — реализация интерфейса (назовём её пользовательской)
ParentB — другая реализация этого же интерфейса (назовём библиотечной)
и тут приспичело иметь объект ParentA, но с реализацией интерфейса взятым из библиотеки т.е., то что зовётся Child
вот такая задача.
решить её можно описав метод интерфейса в классе Child и в его реализации явно вызвать нужный метод родителей.
но смущает одно — библиотека (ParentB) создавалась, что бы не надо было в потомках заботиться о реализации интерфейса и оградить программиста от забот об интерфейсе (base) вообще.
что посоветуете? |
|
olegenty |
Отправлено: 21.10.2004, 06:47 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
посмотри loki, может поможет функция построения иерархии классов, может — какой темплейт. ответ навскидку, но что-то слегонца подобное там было... Только без пояснений Александреску там легко заблудиться.
|
|
Asher |
Отправлено: 21.10.2004, 09:01 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Привет.
Затык здесь?
QUOTE | class Child:virtual public ParentA, virtual public ParentB{}; |
обычная неоднозначность при множественном наследовании.
Решается определением новой функции в производном классе, с последующим вызовом (или невызовом) необходимых функций предков.
CODE | class Child:virtual public ParentA, virtual public ParentB{
public:
void M(void){
ParentA::M();//Вызов метода одного предка
ParentB::M();//Вызов метода другого предка
cout<<"qwe+dfg"<<endl;//Что-нибудь от себя
};
}; |
Если есть возможность вывести функции из virtual, то они не пересекаются, и вызвать их можно как [CODE]
v[i]->ParentA::M();
и, соотвественно,
v[i]->ParentB::M();
[CODE]
P.S. Страуструп. 3-е издание. 15.2.1. Разрешение неоднозначности.
стр 445.
|
|
Георгий |
Отправлено: 21.10.2004, 19:50 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
CODE | void M(void){
ParentA::M();//Вызов метода одного предка
};
| вот как раз от такого кода и хочу избавиться.
ж***й чую, что можно что то с иерархией сделать и всё будет Ок...
похоже подъём реализации ParentA выше по иерархии, чем то место где интерфейс ParentA берёт Child, поможет. |
|
Георгий |
Отправлено: 22.10.2004, 01:01 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
действительно описание интерфейса без реализации дало мне то что хотел:CODE | #include <iostream.h>
class base
{
public:
virtual void M(void)=0;
};
class InterfaceA
{
virtual void interfaceA(void)=0;
};
class ParentA:virtual public base
{
public:
void M(void){cout<<"ParentA"<<endl;};
void interfaceA(void){cout<<"interfaceA implementation1"<<endl;};
};
class ParentB:virtual public base
{
public:
void M(void){cout<<"ParentB"<<endl;};
};
class Child:virtual public InterfaceA, virtual public ParentB
{
public:
void interfaceA(void){cout<<"interfaceA implementation2"<<endl;};
};
class OldChild:virtual public ParentA, virtual public ParentB
{
public:
void interfaceA(void){cout<<"interfaceA implementation2"<<endl;};
};
void main(void)
{
Child c;
c.M();
c.interfaceA();
OldChild oc;
oc.M();
oc.interfaceA();
}; |
соответственно Child теперь то что надо, а OldChild то, что не надо.
Отредактировано Георгий — 22/10/2004, 02:04
Присоединить изображение
|
|
olegenty |
Отправлено: 22.10.2004, 07:16 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
А ларчик просто открывался.
|
|
Asher |
Отправлено: 22.10.2004, 10:11 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Привет.
Что-то я не понял решения проблемы.
OldChild oc; как в исходной постановке задачи вы все равно создать не сможете — а то что вы сделали — это просто чистый абстрактный класс для предоставления общего интерфейса.
Могли и не выдумывать, а просто прочесть 12.3. Абстрактные классы.
В конце главы на стр. 362.
И, более подробно, 15.2.5. Испрользование множественного наследования, 15.2.5.1. Замещение функций виртуальных базовых классов.
|
|
Георгий |
Отправлено: 22.10.2004, 23:18 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
верно — это не решение, а фигня какая то.
что есть что:
base — частично реализованный интерфейс для хранения объектов. некоторые методы должны быть реализованы в потомках, например "M".
InterfaceA — абстрактный интерфейс обработки данных.
ParentA — полностью определённый объект выполняющий обработку данных по заданному алгоритму и позволяющий свои параметры сохранять/восстанавливать
и вот после реализации все этого обнаружил, что нету у меня контейнера позволяющего сохранить/загрузить множество ParentA. Контенеры так же должны быть рекурсивными — позволять хранить сами себя (по интерфейсам не отличаться от ParentA).
реализовать это решил так:
1. использовать класс ParentB, являющийся гибридом контейнера и фабрики классов, позволяющий сохранять/восстанавливать объекты с заданным общим предком.
2. ретранслировать вызовы interfaceA на элементы контейнера
результат этой деятельности зовётся OldChild
и на него компилятор ругался такими словами, что и не знал что думать
конечно же спокойный разбор выявил получившийся конфликт, например интерфейсный метод "M" реализован в обоих предках и моё желание прозрачно использовать библиотечный (ParentB::M) было незамечено со стороны транслятора
решение "в лоб" — явно указать в OldChild какой метод вызывать, мне непонравилось, хотя бы потому, что однажды узаконненый дефект конструкции ни к чему хорошему потом не приводит. вот я и игнорировал Ваши предложения переопределить в OldChild метод "M" и уже в нём вызвать правильный интерфейсным метод "M".
"решение", что привёл в своём предыдущем посте было откровенным бредом — небыло возможности работать с ParentA и Child единообразно, да и бриллиант разбился
спокойно подумав на работе решил бриллиант восстановить, а ParentA сместить ниже (или если угодно выше), а на его место поставить его абстрактный интерфейс, через который моно будет работать единообразно и с ParentA и с Child.
получается вот что:
новый интерфейс IntAB — представляет интерфейс base и то, что раньше было отличной от base частью ParentA, но не имеет никаких реализаций (чтоб конфликтов, как в "Страуструп. 3-е издание. 15.2.1. Разрешение неоднозначности.
стр 445." и в "12.3. Абстрактные классы. В конце главы на стр. 362." небыло).
ParentA — банальная реализация интрфейса IntAB
и новый Child — наследующий от ParentB реализацию методов base и берущий интерфейс ParentA от IntAB.
в итоге бриллиант восстановлен, конфликтов нет и, даже, успел поиграться с получившимся монстром и убедиться, что оно работает
Спасибо.
PS. а вот и рисунок:
PPS. О, да — OldChild только демонстрация как было и как делать не надо
Отредактировано Георгий — 23/10/2004, 00:27
Присоединить изображение
|
|
|