Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.08.29;
Скачать: CL | DM;

Вниз

Множественное наследование: почему его нет?   Найти похожие ветки 

 
KSergey ©   (2004-08-10 12:48) [0]

А вот мой коллега задался иным вопросом: а почему в дельфи нет мнжественного наследования? Это лишь религия, или здесь есть более глубинные смыслы (читай: принципиальные технические ограничения) в построении виртуальной таблицы/распределении памяти/однопроходности компиляции и п.т.?


 
имя   (2004-08-10 12:57) [1]

Удалено модератором


 
jack128 ©   (2004-08-10 13:09) [2]


> НЕутУТь_НикАСперли  
ну ведь на плюсах конфликты имен как то решаются ;-)


 
Думкин ©   (2004-08-10 13:10) [3]

> как то решаются


 
имя   (2004-08-10 13:12) [4]

Удалено модератором


 
Ega23 ©   (2004-08-10 13:13) [5]

Если честно, пока ещё не сталкивался с практической задачей, где самым изящным решением было бы множественное наследование.


 
Mihey_temporary ©   (2004-08-10 13:17) [6]



TMyClass1 = class
procedure do();
end;

TMyClass2 = class
procedure do();
end;

TMyClass3 = class(TMyClass1,TMyClass2)
procedure DoSomeThing();
end;

.....
procedure TMyClass3.DoSomeThing();
begin
do(); <----- кто виноват? что делать? едят ли курицу руками?
end;



А почему бы этому коду не выполнить Do() сразу двух классов, можно по-порядку.


 
Игорь Шевченко ©   (2004-08-10 13:19) [7]

Mihey_temporary ©   (10.08.04 13:17) [6]

А зачем смешивать классы с одинаковыми методами ?


 
ламер ©   (2004-08-10 13:19) [8]

> Ega23 ©   (10.08.04 13:13) [5]
честно говоря, я пока ещё вообще не встречал задач, в которых требовалось бы множественное наследование. :) всегда хватает интерфейсов.


 
Mihey_temporary ©   (2004-08-10 13:20) [9]

>А зачем смешивать классы с одинаковыми методами ?

Одинаковое название, но не сама реализация.


 
Anatoly Podgoretsky ©   (2004-08-10 13:29) [10]

Игорь Шевченко ©   (10.08.04 13:19) [7]
Это не принципиально и в рамках ООП


 
kirasuki ©   (2004-08-10 13:45) [11]

Опять же ничего не буду говорить о месте множественного наследования в ООП, у него есть свои недостатки и приемущества. Однако если посмотреть MFC hierachy chart (MSDN), то вы найдете там пару классов, имеющих двух предков.
А методы базовых классов, имеющие одинаковые имена в C++ вызываются примерно так:

class A {
public:
 void do() {}
};

class B {
public:
 void do {}
};

class C: public A, public B {};

C c;

с.A::do() // метод родителя A
с.B::do() // метод родителя B


 
kirasuki ©   (2004-08-10 13:47) [12]

Простите за очепятки, меня несчастного.

class A {
public:
void do() {}
};

class B {
public:
void do() {}
};

class C: public A, public B {};

C c;

с.A::do(); // метод родителя A
с.B::do(); // метод родителя B


 
Игорь Шевченко ©   (2004-08-10 13:47) [13]

kirasuki ©   (10.08.04 13:45) [11]


> А методы базовых классов, имеющие одинаковые имена в C++
> вызываются примерно так:


Да я вообще-то не об этом, а зачем смешивать их, создавая себе лишние проблемы ?


 
kirasuki ©   (2004-08-10 13:49) [14]

Это может не зависеть от программиста, которому достался код с плохой "наследственностью".


 
DiamondShark ©   (2004-08-10 13:57) [15]


> Да я вообще-то не об этом, а зачем смешивать их, создавая
> себе лишние проблемы ?

Да незачем. Просто может так оказаться, что вот захотелось создать множественного наследника, а в предках -- бац! -- одинаковые методы.

Кстати, как эта ситуация в Ц++ обрабатывается? Компилируется или ругается?


 
icWasya ©   (2004-08-10 15:14) [16]

Для чего нужно - ну например посмотрите на закладку компонент DataControls. И посмотрите на реализацию этих компонент. В каждом компоненте есть код доступа к полю таблицы. Но TDBLabel наследуется от TCustomLabel, TDBEdit от TCustomEdit и.т.д. И у них НЕТ общего предка типа TFieldLink! И если пишется компонент типа TDBCtrlGrid, которому нужно знать - является ли компонент DataAware, то узнаётся это не через механизм наследования, as-is , а через сообщения, причём код обработки этого сообщения (CM_GETDATALINK) во всех компонентах абсолютно одинаковый

procedure TDB_xxx.CMGetDataLink(var Message: TMessage);
begin
 Message.Result := Integer(FDataLink);
end;

бери и делай общего предка, но....
ИМХО


 
Игорь Шевченко ©   (2004-08-10 15:50) [17]

DiamondShark ©   (10.08.04 13:57) [15]


> Кстати, как эта ситуация в Ц++ обрабатывается? Компилируется
> или ругается?


Ругается:
myprojects\testinheritance\testinheritance.cpp(23) : error:  "C::Do" is ambiguous
myprojects\testinheritance\testinheritance.cpp(23) : warning : could be the "Do" in base "A" of class "C"
myprojects\testinheritance\testinheritance.cpp(23) : warning : or the "Do" in base "B" of class "C"

// TestInheritance.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

class A {
public:
int Do (void) { return 1; }
};

class B {
public:
int Do (void) { return 2; }
};

class C: public A, public B {
};

int main(int argc, char* argv[])
{
C CInstance;

printf("Hello World, it\"s %d!\n", CInstance.Do());

return 0;
}


 
Igorek ©   (2004-08-10 17:50) [18]


> Игорь Шевченко ©   (10.08.04 13:47) [13]
> Да я вообще-то не об этом, а зачем смешивать их, создавая
> себе лишние проблемы ?

class T4WheelsCar {
 private:
   bool GoodWheels(void) { /*some diagnostic*/ return true; };
 protected:
   bool WantRepair() { return GoodWheels(); };
};

class TSunBatteryVehicle {
 private:
   bool GoodSunBatteries() { /*some diagnostic*/ return true; };
 protected:
   bool WantRepair() { return GoodSunBatteries(); };
};

class TSunCar: public T4WheelsCar, TSunBatteryVehicle {
 protected:
   bool WantRepair() { return T4WheelsCar::WantRepair() && TSunBatteryVehicle::WantRepair(); };
};


 
Игорь Шевченко ©   (2004-08-10 18:01) [19]

Igorek ©   (10.08.04 17:50) [18]

Вот смотри: в классах T4WheelsCar и TSunBatteryVehicle у тебя методы Good с суффиком. А почему метод WantRepair без суффикса ?


 
Mystic ©   (2004-08-10 19:00) [20]

А зачем смешивать классы с одинаковыми методами ?

Например в Dephi все классы порождены от TObject. Деструктор Destroy у него виртуальный. Если класс порожден от TSomeClass1 и TSomeClass2 и оба перекрывают деструктор, то...

Надо как и в С++ иметьвозможность делать наследование виртуальным. За этим надо следить, ... В целом усложнение языка налицо. А вот реальную пользу можно извлечь в ограниченом количестве случаев. Я, например, против привнесения таких возможностей в язык только для того, чтобы было. Язык должен быть по возможности простым.


 
Igorek ©   (2004-08-11 15:43) [21]


> Игорь Шевченко ©   (10.08.04 18:01) [19]
> Igorek ©   (10.08.04 17:50) [18]
>
> Вот смотри: в классах T4WheelsCar и TSunBatteryVehicle у
> тебя методы Good с суффиком. А почему метод WantRepair без
> суффикса ?

Ну это пример. Метод WantRepair отвечает - надо ли ремонтировать механизм вообще. Для любого класса-механизма такой метод один.
А механизм может иметь несколько частей.
Напр. в классе T4WheelsCar могли бы быть две оси. Тогда был бы еще метод:

GoodAxises() {return GoodAxisFront(/*диагностика*/) && GoodAxisBack(/*диагностика*/); }

Ну и метод WantRepair был бы такой:

bool WantRepair() { return GoodWheels() && GoodAxises(); };

А в наследнике общее состояние состоит из лог. суммы состояний частей.

На самом деле тут налицо проблемма "агрегация vs наследование". Если однотипные обьекты наследуются, то в наследнике вызываются все одинаковые методы предков.
Если агрегируются, то два варианта:
1) агрегируются классы - вызываем все одинаковые методы для полей обьектов
2) агрегируются поля - вызываем конкретную функцию для каждой части

---
я когда писал пример специально привел область, где наследование очевиднее и лучше агрегации


 
Игорь Шевченко ©   (2004-08-11 16:00) [22]


> Ну это пример. Метод WantRepair отвечает - надо ли ремонтировать
> механизм вообще. Для любого класса-механизма такой метод
> один.


Метод Good, насколько я понимаю, отвечает, является ли механизм исправным вообще ?

> bool WantRepair() { return GoodWheels() && GoodAxises();
> };


По логике здесь все-таки агрегация предпочтительней.

Тогда bool WantRepair () { return !Wheels.Good() || !Axises.Good(); }

И не WantRepair, а NeedsRepair :)


 
DiamondShark ©   (2004-08-11 17:54) [23]

Вообще-то, примерчик на типичную агрегацию.
Так что всё интерфейсами делаем ;)


 
Cobalt ©   (2004-08-11 18:14) [24]

А деструктор по умолчанию - Destroy?


 
DiamondShark ©   (2004-08-11 18:48) [25]


> А деструктор по умолчанию - Destroy?

В паскале отсутствует понятие "деструктор по умолчанию".


 
Cobalt ©   (2004-08-11 20:48) [26]

А как же тогда быть с классами, исполняющими интерфейсы? Их же не уничтожают ручками. А память, выделенную под них, наверное, освобождают как-то корректно?

P.S.
2 DiamondShark © - а у тебя вся спина белая (анкеты нету)



Страницы: 1 вся ветка

Текущий архив: 2004.08.29;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.03 c
4-1090172218
Makhanev A.S.
2004-07-18 21:36
2004.08.29
Как запустить службу сразу после её инсталляции?


1-1092317777
Alex____
2004-08-12 17:36
2004.08.29
Принцып работы архиватора.


14-1092296447
syte_ser78
2004-08-12 11:40
2004.08.29
помогите с проблемкой. Подскажите утилитку


9-1084221010
Werwolf
2004-05-11 00:30
2004.08.29
Ворпос на засыпку....


4-1090235980
Deep8
2004-07-19 15:19
2004.08.29
RESET