Чтение онлайн

на главную

Жанры

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

Григорьев Антон Борисович

Шрифт:

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

Поделиться:
Популярные книги

Санек 2

Седой Василий
2. Санек
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Санек 2

Князь Мещерский

Дроздов Анатолий Федорович
3. Зауряд-врач
Фантастика:
альтернативная история
8.35
рейтинг книги
Князь Мещерский

Без Чести

Щукин Иван
4. Жизни Архимага
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Без Чести

Безродный

Коган Мстислав Константинович
1. Игра не для слабых
Фантастика:
боевая фантастика
альтернативная история
6.67
рейтинг книги
Безродный

Огненный князь

Машуков Тимур
1. Багряный восход
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Огненный князь

Ваше Сиятельство 4т

Моури Эрли
4. Ваше Сиятельство
Любовные романы:
эро литература
5.00
рейтинг книги
Ваше Сиятельство 4т

Вторая невеста Драконьего Лорда. Дилогия

Огненная Любовь
Вторая невеста Драконьего Лорда
Любовные романы:
любовно-фантастические романы
5.60
рейтинг книги
Вторая невеста Драконьего Лорда. Дилогия

Кодекс Крови. Книга V

Борзых М.
5. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга V

Девятое правило дворянина

Герда Александр
9. Истинный дворянин
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Девятое правило дворянина

Цеховик. Книга 1. Отрицание

Ромов Дмитрий
1. Цеховик
Фантастика:
попаданцы
альтернативная история
5.75
рейтинг книги
Цеховик. Книга 1. Отрицание

Скрываясь в тени

Мазуров Дмитрий
2. Теневой путь
Фантастика:
боевая фантастика
7.84
рейтинг книги
Скрываясь в тени

Убивать чтобы жить 2

Бор Жорж
2. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 2

Идеальный мир для Лекаря 3

Сапфир Олег
3. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 3

Под маской, или Страшилка в академии магии

Цвик Катерина Александровна
Фантастика:
юмористическая фантастика
7.78
рейтинг книги
Под маской, или Страшилка в академии магии