Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2009.03.15;
Скачать: [xml.tar.bz2];

Вниз

непереопределённые обстрактные методы   Найти похожие ветки 

 
oxffff ©   (2009-01-15 12:51) [40]


> Alkid ©   (15.01.09 12:26) [37]
>
> > oxffff ©   (15.01.09 11:02) [35]
> >
> > Смысл простой это вопрос идеалогии. [34]
>
> Я, вот, одного не понимаю - какой смысл разработчику создавать
> экземпляр класса с абстрактными методами? Мне бы очень хотелось
> бы узнать прецеденты, где какие-нибудь архитектурные задачи
> решались через создание экземпляров абстрактных классов.
>  Пока же я твёрдо убеждён, что сама возможность так делать
> - зло.


Существуют алтернативные мнения. [29]
Задача инструмента предоставить выбор.


 
Ega23 ©   (2009-01-15 12:55) [41]


> Если в классе присутствуют абстрактные методы, то инстанцировать
> класс нельзя, потому, что это ведёт к неминуемым ошибкам


unit 1.

TFoo = class (TObject)
public
 constructor Create; virtual;
 procedure DoSomething; virtual; abstract;
end;

TFooClass = class of TFoo;

TFooChild = class (TFoo)
public
 procedure DoSomething; override;
end;

implementation

constructor TFoo.Create;
begin
 inherited Create;
end;

procedure TFooChild.DoSomething;
public
 ... Чё-та делаем
end;

unit 2.

TMySuperPuperClass = class (....)
private
 FFoo : TFoo;
public
 constructor Create(FooClass : TFooClass);
 property Foo : TFoo read FFoo;
end;

constructor TMySuperPuperClass.Create(FooClass : TFooClass);
begin
 FFoo := FooClass.Create;
end;

unit 3

procedure Tform1.OnButton1Click(Sender : TObject)
begin
 wtih TMySuperPuperClass.Create(TFooChild) do
 begin  
   try
     Foo.DoSomething;
   finally
     Free;
   end;
 end;
end;



 
Игорь Шевченко ©   (2009-01-15 12:57) [42]

XentaAbsenta ©   (15.01.09 12:44) [39]

Выброси свой здравый смысл - конкретный наследник абстрактного класса может находиться в BPL и конструкция может выглядеть так:

type
 TFoo = class
 protected
    procedure Bar; abstract;
 end;

 TFooClass = class of TFoo;

.....
var
 FooClass: TFooClass;
 Foo: TFoo;
...
 FooClass := GetFooClassFromExternalSource;
 
 Foo := FooClass.Create;
...


Мне было бы крайне любопытно узнать, как при компиляции данного кода  проверить, является ли инстанцируемый класс абстрактным или содержит непереопределенные абстрактные методы


 
tesseract ©   (2009-01-15 12:58) [43]


> Это не вопрос идеалогии, это вопро здравого смысла. Если
> в классе присутствуют абстрактные методы, то инстанцировать
> класс нельзя, потому, что это ведёт к неминуемым ошибкам,
>


При наличии остуствия факт имеет место быть! Например  виртуальные методы и все события - суть абстракция. Их при создании класса может и не быть.


 
KSergey ©   (2009-01-15 13:05) [44]

> XentaAbsenta ©   (15.01.09 12:44) [39]
> компилятор ... ни при
> каких обстоятельствах не позволять инстанцировать класс даже через ссылку на класс

Штука в том, что компилятор дельфи в принципе не може этого знать в случае ссылки на класс. Ega23 ©   (15.01.09 12:55) [41] даже пример написал.

В синтаксисе С++ такого нет в приницпе, потому там все иначе.


 
tesseract ©   (2009-01-15 13:07) [45]


> Ega23 ©   (15.01.09 12:55) [41] даже пример написал.


Ага мне особенно  wtih  понравился - зачем на такой вопрос такой подробный код ? Тем более,  что есть ещё например AS.


 
KSergey ©   (2009-01-15 13:13) [46]

> Игорь Шевченко ©   (15.01.09 12:57) [42]
> класса может находиться в BPL и конструкция может выглядеть так:

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


 
Alkid ©   (2009-01-15 13:15) [47]


> Игорь Шевченко ©   (15.01.09 12:57) [42]

Всё просто - попытка инстанциировать абстрактный класс - исключительная ситуация. Т.е. позволять создавать экземпляр нельзя никак. Если нельзя проверить этот факт в Compile-time, надо проверять его в Run-Time. Но экземпляр абстрактного класса не должен получаться ни при каких обстоятельствах.


> oxffff ©   (15.01.09 12:51) [40]

В [29] описана ситуация с неправильно спроектированной структурой классов и "хакерский" подход при работе с ней. Данная практика, ИМХО, порочна, поскольку является раскладыванием граблей на будущее, что бы на них можно было самому потом смачно наступить, когда ты уже забудешь про свой гениальный ход. Ну или для ближнего своего грабля получится, когда он на это напорется.

По сути ты предлагаешь создать объект, который не выполняет опубликованного контракта (интерфейса). Это небезопасный ход, который требует от тебя постоянно держать в голове тот факт, что для данного объекта действует только часть интерфейса.


 
tesseract ©   (2009-01-15 13:20) [48]


> Это небезопасный ход, который требует от тебя постоянно
> держать в голове тот факт, что для данного объекта действует
> только часть интерфейса.


Работу с VMT уже считают хакерским методом, а было  время когда других способов и не было.  То же  OLE  на позднем связывании и базируеться. В  Objective-C   или скриптовых все классы вообще тотальная абстракция - но работает же.


 
Ega23 ©   (2009-01-15 13:28) [49]


> Ага мне особенно  wtih  понравился - зачем на такой вопрос
> такой подробный код ? Тем более,  что есть ещё например
> AS.


А чё не так? И as при чём?


 
tesseract ©   (2009-01-15 13:30) [50]


> А чё не так? И as при чём?


По документации он безопастнее.


 
Ega23 ©   (2009-01-15 13:32) [51]


> По документации он безопастнее.


безопаснее ЧЕГО?


 
icWasya ©   (2009-01-15 13:37) [52]

А вот такое имеет право на существование ?


unit Classes;
...
TStream = class(TObject)
 private
 ...
 public
   function Read(var Buffer; Count: Longint): Longint; virtual; abstract;
   function Write(const Buffer; Count: Longint): Longint; virtual; abstract;
   function Seek(Offset: Longint; Origin: Word): Longint; virtual; abstract;

и
TPointerStream = Class(TStream)
...
piblic
   constructor Create(aP:Pointer;aSize:LongInt);
   function Read(var Buffer; Count: Longint): Longint; override;
   function Seek(Offset: Longint; Origin: Word): Longint; override;
end;

причём я точно знаю, что Write никогда не будет использоваться.


 
Alkid ©   (2009-01-15 13:44) [53]


> tesseract ©   (15.01.09 13:20) [48]
> Работу с VMT уже считают хакерским методом, а было  время
> когда других способов и не было.

А вот отсюда поподробнее пожалуйста. Впервые слышу, что работа с VMT уже считается хакерским методом :) Что ты подразумеваешь по работой с VMT?


> То же  OLE  на позднем
> связывании и базируеться. В  Objective-C   или скриптовых
> все классы вообще тотальная абстракция - но работает же.

На позднем связывании вообще значительная часть полиморфизма работает. И VMT - это лишь один из вариантов механизма позднего связывания. Он эффективен по скорости выполнения, но зато сильно ограничен. Например, multiple dispatch на нём закачаешься делать.

Касаемо скриптовых языков - это от языка зависит. Да, есть "безклассовые" ОО-языки. Их ещё называют ОО с прототипированием. Но там есть свои остроумные способы разобраться с попыткой применить к объекту метод, который в нём (для него) не определён. К теме этого разговора это всё не имеет прямого отношения.


 
Ega23 ©   (2009-01-15 13:45) [54]


> причём я точно знаю, что Write никогда не будет использоваться.


ага, а также WriteBuffer и CopyFrom?


 
tesseract ©   (2009-01-15 13:45) [55]


> безопаснее ЧЕГО?


Безопаснее  прямого  typecasting,


> А вот такое имеет право на существование ?


Это абстрактный класс перекрываемый наследниками. Abstarct error  можно вызвать не напрягаясь, но дело не в этом.


 
Anatoly Podgoretsky ©   (2009-01-15 13:51) [56]

> Ega23  (15.01.2009 13:32:51)  [51]

Безопаснее приведения.


 
Mystic ©   (2009-01-15 13:54) [57]

> По сути ты предлагаешь создать объект, который не выполняет
> опубликованного контракта (интерфейса). Это небезопасный
> ход, который требует от тебя постоянно держать в голове
> тот факт, что для данного объекта действует только часть
> интерфейса.


Во-первых, объект выполняет опубликованный интерфейс полностью. Просто у абстрактных методов реализация по умолчанию кидать exception. Я эту реализацию просто не меняю.

Во-вторых, ход как ход. Такой подход может быть полезным в разработке и в unit-тестах. Например, я создаю наследника от некоторого класса. Разработку веду по частям, вначале отлаживаю одну группу методов. Соответственно зачем мне вначале делать реализации всех абстрактных методов и помещать в каждый из них вызов raise ENotImplemented.Create() ???

В-третьих, это исключение можно ловить и обрабатывать. Т. е. использовать как часть логики. Дернули метод, получили EAbstractError, значит этот метод эту фичу не поддерживает. Или, по другому, опросили, что класс поддерживает. Узнали, что сортировка не поддерживается. Если все-таки вызвали метод Sort, то получили сигнал об ошибке---EAbstractError.

Как по мне, надо просто поменять точку зрения. В Delphi абстрактный метод имеет реализацию, это возбуждение исключения EAbstractError. Считай, что это вариант ENotImplemented. И используй. А чистых виртуальных методов а-ля С++ в Delphi нет.


 
Ega23 ©   (2009-01-15 13:54) [58]


> Безопаснее приведения.


Я не понял, а где у меня приведение (явное)?


 
tesseract ©   (2009-01-15 13:57) [59]


> Я не понял, а где у меня приведение (явное)?


> wtih TMySuperPuperClass.Create(TFooChild) do


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


 
Alkid ©   (2009-01-15 14:02) [60]


> Mystic ©   (15.01.09 13:54) [57]

Я понимаю твою точку зрения, но она напрямую противоречит уже заложенной в Дельфи философии на явность всех декларций. Overload, override, reintroduce и т.п. Т.е. программист явно говорит, что он тут хочет сказать, что бы не вышло случайной перегрузки или переопределения. То, что ты предлагаешь идёт вразрез с этой философией, по-этому я считаю это недосмотром с точки зрения разработчиков языка. Предлагаемый тобой подход в бОльшей степени подошёл бы C++, где компилятор без лишних деклараций делает выводы о перегрузке/переопределении.

Собственно говоря, всё это лишний раз подтверждает, что дисциплина поддержания идеологической целостности и чистоты в Дельфи хромает.


 
KSergey ©   (2009-01-15 14:07) [61]

> tesseract ©   (15.01.09 13:57) [59]
> > wtih TMySuperPuperClass.Create(TFooChild) do
> Прямо вот тут абсолютное приведение с моторчиком.

Здрасьте, приехали. Вчитайтесь в код внимательнее. Просто параметр передается в конструктор, никакого приведения нет.


 
XentaAbsenta ©   (2009-01-15 14:08) [62]

Игорь Шевченко ©   (15.01.09 12:57) [42]

> Мне было бы крайне любопытно узнать, как при компиляции
> данного кода  проверить, является ли инстанцируемый класс
> абстрактным или содержит непереопределенные абстрактные
> методы
>


Гороздо любопытнее то, как удалось так скомпилить bpl, так что в него не попало определение одного из базовых классов, или почему это позволил сделать компилятор.   Вот это уж точно здравому смыслу противоречит.
Скажите, уважаемый а что будет если я изменю код предка до неузнаваемости т.е.: в bpl находится класс T2, который наследуется от T1, я беру и уродую T1, сохраняя название класса, после чего компилирую(?!) и запускаю? А такая ситуация не редкость при переработке проекта, ногда базовые классы менять таки приходится.

Ega23 ©   (15.01.09 12:55) [41]
Приведённый код ничего не показывает. T = class of TMyAbstractClass;
T должно содержать признак абстрактности класса


 
Ega23 ©   (2009-01-15 14:12) [63]


> Прямо вот тут абсолютное приведение с моторчиком.


Макс, ты чё? Ты код мой внимательно посмотри.


 
Ega23 ©   (2009-01-15 14:13) [64]


> Приведённый код ничего не показывает. T = class of TMyAbstractClass;


И что? Я передаю в конструктор класс со всеми перекрытыми абстрактными методами.


 
tesseract ©   (2009-01-15 14:15) [65]


> Макс, ты чё? Ты код мой внимательно посмотри.


with  попутал. Обычно так и приводиться к знаменателю у меня 38 если что :-)


 
Ega23 ©   (2009-01-15 14:27) [66]


> у меня 38 если что :-)


сантиметров? Ходить не мешает?
:))))))))))))


 
Юрий Зотов ©   (2009-01-15 14:32) [67]

> XentaAbsenta ©   (15.01.09 12:44) [39]

> Если в классе присутствуют абстрактные методы, то инстанцировать
> класс нельзя, потому, что это ведёт к неминуемым ошибкам

Почему неминуемым? Если абстрактный метод реально нигде не вызывается, то и ошибок не будет.

> компилятор должен в таких случаях требовать от программиста посавить
> модификатор abstact в определении класса и ни при каких
> обстоятельствах не позволять инстанцировать класс

В силу предыдущего, компилятор должен выдать предупреждение (что он и делает), но не делать никаких запретов. Программист это предупреждение получает, но решает сам. Ему виднее, что и как он использует.

> даже через ссылку на класс, которая вполне может тоже может нести в
> себе аттрибуты класса.

Игорь уже привел пример, когда на этапе компиляции определить реальный класс невозможно.

> А ошибки времени выполнения отлавливать и исправлять куда сложнее
> нежели ошибки компиляции.

Вот с этим никто не спорит. Но если Вы включите показ варнингов и приучите себя программировать так, чтобы не было не только ошибок, но и даже хинтов (то есть, чтобы окошко сообщений компилятора всегда оставалось пустым), то как раз на этапе компиляции все плюшки и выловите.


 
Mystic ©   (2009-01-15 14:34) [68]


> напрямую противоречит уже заложенной в Дельфи философии
> на явность всех декларций. Overload, override, reintroduce
> и т.п.


А почему ты ничего не говоришь о safecall, inline? Одни модификаторы для явных деклараций, другие заставляют компилятор выполнять некоторые дополнительные действия... И я бы не говорил о какой-то идеологической целостности Delphi. Идеологическая целостность может быть у С++, где есть специальный комитет, который рассматривает предложения и говорит: эту фичу мы вносить не будем, потому что она противоречит идеологической целостности. Delphi, как мне кажется, больше формировался под влиянием практических потребностей. Насколько я помню, абстрактные методы были введены еще в Turbo Pascal. В те времена больше стояла проблема производительности, поэтому мне представляется вполне логичным, что создание объекта не перегружается дополнительными операциями. Delphi 1 изначально был под Win16, проблема производительности и там сохранялась. Более того, даже стала более актуальной ввиду того, что даже небольшие классы стали создаваться в куче. С другой стороны сами абстрактные методы достаточно редко используются в той же самой VCL. Вот и все :)


 
Alkid ©   (2009-01-15 14:38) [69]


> Юрий Зотов ©   (15.01.09 14:32) [67]
> Почему неминуемым? Если абстрактный метод реально нигде
> не вызывается, то и ошибок не будет.

Есть хорошее эвристическое правило - то, что можно сделать, будет сделано рано или поздно. То этот метод нельзя вызывать либо сам забудешь, либо коллега забудет, либо новенький какой-нибудь сотрудник даже знать не будет.


 
Anatoly Podgoretsky ©   (2009-01-15 14:40) [70]


> Ega23 ©   (15.01.09 13:54) [58]

А я не знаю, о каком AS вы говорите, в [41] нет ни оператора AS , ни свойства AS , ни приведения.

Я отвею на вопрос, чем AS безопаснее.


 
Ega23 ©   (2009-01-15 14:47) [71]


> Я отвею на вопрос, чем AS безопаснее.


Не, я знаю что такое as. Что сначала проверка на is, а потом уже typecast. Я Макса не понял.


 
Mystic ©   (2009-01-15 14:51) [72]

> Alkid ©   (15.01.09 14:38) [69]

Ой, в реальном приложении таких мест столько... И абстрактные методы занимают столь малую часть от их числа...


 
icWasya ©   (2009-01-15 14:51) [73]

2 Ega23 ©   (15.01.09 13:45) [54]

>> причём я точно знаю, что Write никогда не будет использоваться.
>ага, а также WriteBuffer и CopyFrom?
ну естественно


 
XentaAbsenta ©   (2009-01-15 14:51) [74]

Григорьев Антон ©   (15.01.09 10:11) [24]


> Это связано с наличием в Delphi метаклассов и виртуальных
> конструкторов. Из-за этого не всегда на этапе компиляции
> можно решить, конструктор какого именно класса вызывается
> - с абстрактными методами, или его потомка, в котором они
> перекрыты. А раз 100%-ый отлов всё равно невозможен, разработчики
> Delphi решили не париться с этим вообще и отлавливать всё
> только в run-time.


T0 : abstract class
T1 : abstract class
T2 : class
----------
T0 содержит виртуальный конструктор Create(var tt : anytype), T1 тоже содержит, а T2 не содержит. В этом случае возможно инстанцирование T1, что недопустимо (напр. через ссылку на класс).
Выходом может быть ошибка компиляции класса T2 c требованием переопределить к виртуальный конструктор Create(var tt : anytype).
Что в купе с прямым запретом к инстанцированию абстрактных классов, приведёт к принципиальной невозможности их инстанцирования.

------------------
насчёт идеалогии - на кой ляд тогда нужно слово абстракт, для красоты?


 
Anatoly Podgoretsky ©   (2009-01-15 14:54) [75]

> Ega23  (15.01.2009 14:47:11)  [71]

А я подумал, что ко мне претензии.


 
Ega23 ©   (2009-01-15 14:55) [76]


> насчёт идеалогии - на кой ляд тогда нужно слово абстракт,
>  для красоты?


О! Это уже другой вопрос. Поройся в архиве, я весной эту тему поднимал. Достаточно жаркая дискуссия была. Как в виртуале, так и потом в реале.


 
XentaAbsenta ©   (2009-01-15 14:56) [77]

74
а это уже приведёт к принципиальной невозможности получить EAbstractError


 
Юрий Зотов ©   (2009-01-15 14:58) [78]

> Alkid ©   (15.01.09 14:38) [69]

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

Но как раз на такой случай варнинги и существуют. И этого достаточно.


 
Юрий Зотов ©   (2009-01-15 15:11) [79]

> XentaAbsenta ©   (15.01.09 14:51) [74]

> В этом случае возможно инстанцирование T1, что недопустимо (напр.
> через ссылку на класс). Выходом может быть ошибка компиляции класса
> T2 c требованием переопределить к виртуальный конструктор Create
> Что в купе с прямым запретом к инстанцированию абстрактных классов,
> приведёт к принципиальной невозможности их инстанцирования.

Даже если в T2 перекрыть конструктор, создать экземпляр T1 через ссылку на класс все равно будет можно. И на этапе компиляции будет невозможно отследить, экземпляр какого именно класса создается.

> на кой ляд тогда нужно слово абстракт, для красоты?

На тот ляд оно нужно, чтобы в НЕабстрактных методах абстрактного класса было можно вызывать его же абстрактные методы.

TFigure = class
private
 FSize: ...
 procedure SetSize(...);  
public
 procedure Draw; virtual; abstract;
 property Size: ... read FSize write SetSize;
end;

TCircle = class(TFigure)
public
 procedure Draw; override;
end;

procedure TFigure.SetSize(...);  
begin
 ...
 Draw; // Вот зачем нужен абстрактный метод
end;

procedure TCircle.Draw;
begin
 ... // реальная отрисовка
end;


 
oxffff ©   (2009-01-15 15:23) [80]


> Alkid ©   (15.01.09 13:15) [47]
>
> > oxffff ©   (15.01.09 12:51) [40]
>
> В [29] описана ситуация с неправильно спроектированной структурой
> классов и "хакерский" подход при работе с ней. Данная практика,
>  ИМХО, порочна, поскольку является раскладыванием граблей
> на будущее, что бы на них можно было самому потом смачно
> наступить, когда ты уже забудешь про свой гениальный ход.
>  Ну или для ближнего своего грабля получится, когда он на
> это напорется.
>
> По сути ты предлагаешь создать объект, который не выполняет
> опубликованного контракта (интерфейса). Это небезопасный
> ход, который требует от тебя постоянно держать в голове
> тот факт, что для данного объекта действует только часть
> интерфейса.


Я же говорю есть разные точки зрения. Жестокая декомпозиция приводит к потере эффективности. Поэтому нужна середина между гибкостью и эффективностью кода, размера приложения.
Мне ничего не стоит в этом классе вынести дополнительно контракт интерфейс(часть функциональности) и работать с ним.
Хотя я разделяю обе точки зрения, считаю что и так плохо и так плохо и в тоже время и так хорошо и так хорошо. :)
В вообщем в зависимости от условий делаю выбор. Самое главное, что есть средство которое это предоставляет.



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

Форум: "Прочее";
Текущий архив: 2009.03.15;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.65 MB
Время: 0.069 c
2-1233132678
engine
2009-01-28 11:51
2009.03.15
MCISendString с флагом notify


6-1200389418
chemelin
2008-01-15 12:30
2009.03.15
Помогите с winsocket в WinAPI


15-1231851161
Boris
2009-01-13 15:52
2009.03.15
Помогите найти лучший вариант таблицы


2-1232454342
AnatoliyV
2009-01-20 15:25
2009.03.15
HTML в RES файл


3-1216589956
Dmitry S
2008-07-21 01:39
2009.03.15
Помогите с запросом (бд MySQL)





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский