А. Григорьев - О чём не пишут в книгах по Delphi

Тут можно читать онлайн А. Григорьев - О чём не пишут в книгах по Delphi - бесплатно ознакомительный отрывок. Жанр: comp-programming, издательство БХВ-Петербург, год 2008. Здесь Вы можете читать ознакомительный отрывок из книги онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    О чём не пишут в книгах по Delphi
  • Автор:
  • Жанр:
  • Издательство:
    БХВ-Петербург
  • Год:
    2008
  • Город:
    СПб
  • ISBN:
    978-5-9775-019003
  • Рейтинг:
    4.25/5. Голосов: 81
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 80
    • 1
    • 2
    • 3
    • 4
    • 5

А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание

О чём не пишут в книгах по Delphi - описание и краткое содержание, автор А. Григорьев, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.

Для программистов

О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок

О чём не пишут в книгах по Delphi - читать книгу онлайн бесплатно (ознакомительный отрывок), автор А. Григорьев
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

3.4.8. Ошибка при сравнении указателей на метод

Процедурные типы в Delphi делятся на обычные (унаследованные от Turbo Pascal) и указатели на методы. Первые — что указатели на простые процедуры и функции, вторые — на методы объектов. Чтобы вызвать метод объекта недостаточно знать, где его код располагается в памяти, нужно еще иметь ссылку на конкретный экземпляр класса, к которому относится данный метод (т.е. необходимо значение указателя Self, который будет передан в данный метод). Поэтому указатели на методы называются указателями лишь условно: на самом деле это не один указатель, а два (на код и на объект). Размер переменных такого типа равен 8 байтам, в чем нетрудно убедиться с помощью функции SizeOf.

Очевидно, что два указателя на метод равны тогда и только тогда, когда указывают на один и тот же метод одного и того же объекта, т.е. входящие в них указатели попарно равны. Однако компилятор сравнивает указатели на методы неправильно, и пример MethodPtrCmpна компакт-диске демонстрирует это. На форме этого примера расположены две кнопки класса TButton. Обработчик нажатия на первую из них выглядит так, как в листинге 3.60.

Листинг 3.60. Пример неправильного сравнения указателей на метод

procedure TForm1.ButtonlClick(Sender: TObject);

var

P1, P2: procedure of object;

begin

P1 := Button1.Update;

P2 := Button2.Update;

// Здесь компилятор сравнивает указатели на методы неверно,

// давая ошибочный результат "равно"

if @Р1 = @Р2 then Label1.Caption := 'Равно'

else Label1.Caption := 'Не равно';

end;

Здесь мы получаем указатели на один и тот же метод разных объектов (для примера взяты класс TButtonи метод Update, но подошел бы любой класс и любой метод). Сравнение указателей в этом примере дает ошибочный результат Равно, хотя эти указатели не равны между собой. Просмотр кода, который генерирует компилятор, показывает, что здесь сравниваются только указатели на код метода, а указатели на объекты игнорируются. Так как у нас метод один и тот же, различаются только объекты, то и получается ошибочный результат.

Сравнить указатели на методы правильно можно с помощью типа TMethodиз модуля SysUtils, объявленного следующим образом:

TMethod = record

Code, Data: Pointer;

end;

Так можно получать доступ к отдельным указателям, входящим в указатель на метод. Сравнение указателей на метод с помощью этого типа иллюстрирует листинг 3.61.

Листинг 3.61. Правильный способ сравнения указателей на метод

procedure TForm1.Button2Click(Sender: TObject);

var

P1, P2: procedure of object;

begin

P1 := Button1.Update;

P2 := Button2.Update;

// Правильный способ сравнения указателей на методы

if (TMethod(P1).Data = TMethod(P2).Data) and

(TMethod(P1).Code = TMethod(P2).Code) then

Label1.Caption := 'Равно'

else Label1.Caption := 'He равно';

end;

Здесь мы явным образом заставляем компилятор сравнивать оба указателя, поэтому получаем правильный результат Не равно.

3.4.9. Возможность получения адреса свойства

Пусть у нас есть класс, описанный следующим образом (листинг 3.62).

Листинг 3.62. Класс со свойствами, читаемыми из переменной и из функции

TSomeClass = class private

FProp1: Integer;

function GetProp2: Integer;

public

property Prop1: Integer read FProp1;

property Prop2: Integer read GetProp2;

end;

В этом классе два свойства Prop1и Prop2, значение одного из которых определяется полем FProp1, а другого — функцией GetProp2. Оба свойства предназначены только для чтения, но для того эффекта, о котором здесь пойдет речь, это не принципиально: свойства, значения которых можно менять, ведут себя в этом отношении точно так же.

Пусть X— это переменная типа TSomeClass. Легко убедиться, что компилятор допускает получение адреса свойства Prop1, т.е. конструкция вида @X.Prop1считается допустимой. Результатом выполнении этого оператора станет указатель на поле FProp1. А вот конструкцию @X.Prop2компилятор не допускает, выдаёт ошибку Variable required.

Ошибкой компилятора здесь является то, что он допускает получение адреса в первом случае, т.е. для свойства, значение которой берется из переменной. Это грубейшее нарушение принципа инкапсуляции, лежащего в основе объектно-ориентированного программирования, причем сразу по двум причинам. Во-первых, пользователь класса не должен видеть его внутреннюю реализацию, а здесь пользователь может определить, как читается свойство, по возможности применения оператора @к нему. Во-вторых, пользователь класса должен взаимодействовать с ним строго через предоставленный интерфейс, а у нас получается, что, узнав адрес поля FProp1, пользователь сможет менять его значение в обход предусмотренных для этого в классе механизмов.

К счастью, ситуации, в которых эта недоработка компилятора могла бы принести пользу, крайне редки. Но если вы все-таки столкнулись с такой ситуацией, настоятельно рекомендуем не поддаваться соблазну и искать другие способы решения проблемы. Если класс, к полю которого вы хотите получить доступ таким образом, написан вами, то это веский повод пересмотреть внешний интерфейс класса, т.к. при его проектировании скорее всего, были допущены серьезные ошибки. Если это «чужой» класс, подумайте о том, что в следующей версии этого класса автор может изменить реализация свойства, и тогда ваш код откажется компилироваться.

3.4.10. Невозможность использования некоторых свойств оконного компонента в деструкторе

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

Проблему демонстрирует пример ParentWnd на компакт-диске. В нем создан компонент TWrongCombo, наследник TComboBox. Листинг 5.67 содержит код компонента.

Листинг 3.63. Компонент TWrongCombo

type

TWrongCombo = class(TComboBox)

public

destructor Destroy; override;

procedure AddItem(const Title: string);

end;

destructor TWrongCombo.Destroy;

var

I: Integer;

begin

for I := 0 to Items.Count - 1 do

if Assigned(Items.Objects[I]) then

Dispose(PDateTime(Items.Objects(I]));

inherited;

end;

procedure TWrongCombo.AddItem(const Title: string);

var

P: PDateTime;

begin

New(P);

P^ := Now;

Items.AddObject(Title, TObject(P));

end;

Класс TWrongComboс каждым элементом, добавленным с помощью метода AddItem, связывает значение типа TDateTime, хранящее время добавления элемента. В разд. 3.4.6 мы уже познакомились с возможностью связывания данных с элементом списка с помощью свойства Items.Objects. Но так мы можем связать с элементом только 4-байтное значение, а тип TDateTimeзанимает 8 байтов. Поэтому значение TDateTimeмы будем хранить в динамической памяти, а с элементом свяжем указатель на него.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


А. Григорьев читать все книги автора по порядку

А. Григорьев - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




О чём не пишут в книгах по Delphi отзывы


Отзывы читателей о книге О чём не пишут в книгах по Delphi, автор: А. Григорьев. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x