Класс TObject является базовым для всех, но через него мы можем получить доступ к методам класса более высокого уровня. Давайте посмотрим, как можно приводить классы от одного типа к другому. Создайте новое приложение и поместите на форму одну только кнопку. Теперь создайте для нее обработчик события onclick. Созданная процедура обработки события выглядит следующим образом:
Как мы уже разобрались, в качестве параметра процедура получает указатель на компонент, который сгенерировал событие. Давайте используем этот указатель для того, чтобы изменить свойства класса кнопки. Если вы попробуете написать следующий код:
произойдет ошибка. Это вы точно знаете, что данный обработчик события срабатывает на кнопку, потому что вы создали его именно для кнопки. А вот компилятор даже не пытается это узнать. Он видит, что переменная sender имеет тип TObject, а у этого класса нет свойства тор, поэтому произойдет ошибка.
Как поступить в этом случае? У вас есть множество вариантов, и сейчас мы рассмотрим некоторые из них, а вам остается только выбрать тот, который лучше подходит для данной ситуации, или если подходит любой, то выбирайте тот, что больше нравится.
Начнем с варианта, который можно встретить в большинстве книг:
if Sender is TButton then
(Sender as TButton).Top:=100;
В первой строке проверяем, является ли переменная sender классом TButton. Для этого используется оператор is. Слева от оператора пишется переменная, которую нужно проверить, а справа класс. Если переменная является экземпляром указанного класса, то результатом is будет истина, а значит, выполнится вторая строка кода.
Во второй строке кода самое интересное находится в скобках, где мы говорим, что переменная sender должна восприниматься как класс TButton. Для этого используем оператор as. Теперь, когда мы явно указали, что перед нами объект кнопка, мы можем использовать свойство тор.
На самом деле, если посмотреть на иерархию компонента кнопки, то вы увидите, что свойство тор наследуется от класса TControi. Это значит, что мы можем безболезненно обратиться к свойству, указывая TControi:
if Sender is TControi then
(Sender as TControi).Top:=100;
Это уже лучше. Теперь, если на форму поместить еще один компонент, и в обработчик события onclick установить этот же обработчик события, то все будет работать без проблем. Убедимся? Давайте. Поместим на форму еще одну кнопку TBitBtn со вкладки Additional (Дополнительно). Теперь на вкладке Events (События) установим в качестве обработчика onclick уже созданную ранее процедуру Buttoniciick. Для этого выберите ее имя из ниспадающего списка.
Несмотря на то, что это совершенно другая кнопка (другой класс), все будет работать без проблем. По какой бы кнопке вы не кликнули, та и опустится на расстояние 100 пикселов.
А теперь еще один интересный трюк. А что если обратиться к свойству caption? Но при этом привести класс не к кнопке, а к TLabel:
Такой трюк завершится ошибкой. Дело в том, что оператор as приводит класс, и если классы абсолютно разные, то приведение станет невозможным и произойдет ошибка. Что значит разные классы? Если попытаться привести TBitBtn к TButton, ТО не возникнет проблем, потому ЧТО TBitBtn как раз И происходит ОТ TButton. Если привести TBitBtn к TControi, то тоже не возникнет проблем, потому что TControi является одним из предков. Но кнопка не имеет среди своих предков класс TLabel, а значит, нельзя эти два класса привести друг другу.
Но все же есть один фокус:
Здесь мы приводим кнопку, которая будет указана в переменной sender, к классу TLabel с помощью неявного приведения, которое мы уже рассматривали выше в этой главе. Вот такой трюк пройдет, несмотря на то, что классы совершенно разные. Дело в том, что при таком приведении компилятор всего лишь проверяет, есть ли свойство caption у класса, к которому мы приводим. Если да, то компиляция пройдет удачно. Во время выполнения приведения типов не будет. Программа только будет искать нужное свойство и, если найдет, будет его использовать, поэтому данный код будет корректным.