Читаем О чём не пишут в книгах по Delphi полностью

Нельзя сказать, что разработчики Delphi не знакомы с этой проблемой, они даже что-то делают, чтобы ее решить. Начиная с BDS 2006 можно устанавливать значение свойства WindowState в режиме проектирования, и визуальные компоненты на такой форме будут вести себя интуитивно ожидаемым образом, т.е. адаптироваться к размеру формы, растянутой на весь экран. Правда, с двумя существенными оговорками. Во-первых, свойство Position формы не должно быть равно poDefault или poDefaultSizeOnly. Во-вторых, это относится только к главной форме приложения, для всех остальных форм проблема сохраняется. Поэтому пример WrongAnchors будет работать одинаково и в новых версиях Delphi, и в старых — там на весь экран разворачиваются не главные формы.

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

Процедурные типы в 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;

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

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

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

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

TSomeClass = class private

 FProp1: Integer;

 function GetProp2: Integer;

public

 property Prop1: Integer read FProp1;

 property Prop2: Integer read GetProp2;

end;

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже