МЕНЮ


Фестивали и конкурсы
Семинары
Издания
О МОДНТ
Приглашения
Поздравляем

НАУЧНЫЕ РАБОТЫ


  • Инновационный менеджмент
  • Инвестиции
  • ИГП
  • Земельное право
  • Журналистика
  • Жилищное право
  • Радиоэлектроника
  • Психология
  • Программирование и комп-ры
  • Предпринимательство
  • Право
  • Политология
  • Полиграфия
  • Педагогика
  • Оккультизм и уфология
  • Начертательная геометрия
  • Бухучет управленчучет
  • Биология
  • Бизнес-план
  • Безопасность жизнедеятельности
  • Банковское дело
  • АХД экпред финансы предприятий
  • Аудит
  • Ветеринария
  • Валютные отношения
  • Бухгалтерский учет и аудит
  • Ботаника и сельское хозяйство
  • Биржевое дело
  • Банковское дело
  • Астрономия
  • Архитектура
  • Арбитражный процесс
  • Безопасность жизнедеятельности
  • Административное право
  • Авиация и космонавтика
  • Кулинария
  • Наука и техника
  • Криминология
  • Криминалистика
  • Косметология
  • Коммуникации и связь
  • Кибернетика
  • Исторические личности
  • Информатика
  • Инвестиции
  • по Зоология
  • Журналистика
  • Карта сайта
  • Программирование на Delphi

    ключевое слово default:

    Property Visible:boolean read fVisible write SetVisible default TRUE;

    Это означает, что при запуске программы свойство будет установлено

    компилятором в TRUE.

    Свойство может быть и векторным. В этом случае оно выглядит как массив:

    Property Points[index:integer]:tPoint read GetPoint write SetPoint;

    Для векторного свойства необходимо описать не только тип элементов массива,

    но также и тип индекса. После ключевых слов read и write должны идти имена

    соответствующих методов. Использование здесь полей массивов недопустимо.

    Метод, читающий значение векторного свойства, должен быть описан как

    функция, возвращающая значение того же типа, что и элементы свойства, и

    имеющая единственный параметр того же типа и с тем же именем, что и индекс

    свойства:

    function GetPoint(index:integer):tPoint;

    Аналогично, метод, помещающий значения в такое свойство, должен первым

    параметром иметь индекс, а вторым - переменную нужного типа.

    procedure SetPoint(index:integer; Value:tPoint);

    У векторных свойств есть еще одна важная особенность: некоторые классы в

    Delphi (списки tList, наборы строк tStrings и т.д.) “построены” вокруг

    одного основного векторного свойства. Основной метод такого класса дает

    доступ к элементам некоторого массива, а все основные методы являются как

    бы вспомогательными. Для упрощения работы с объектами подобного класса

    можно описать подобное свойство с ключевым словом default:

    type tMyList=class

    property list[Index:integer]:string read Getlist write Setlist; default;

    end;

    Если у объекта есть такое свойство, его можно не упоминать, а ставить

    индекс в квадратных скобках сразу после имени объекта:

    var MyList:tMyList

    Begin

    MyList.list[1]:=’First’; {Первый способ}

    MyList.[2]:=’Second’; {Первый способ}

    End;

    Употребляя ключевое слово default необходимо соблюдать осторожность, т.к.

    для обычных и векторных свойств оно употребляется в разных значениях.

    О роли свойств в Delphi красноречиво говорит тот факт, что у всех имеющихся

    в распоряжении программиста стандартных классов 100% полей недоступны и

    заменены базирующимися на них свойствами. Того же правила следует

    придерживаться и при разработке собственных классов.

    Наследование

    Вторым “столпом” ООП является наследование. Этот простой принцип означает,

    что если необходимо создать новый класс, лишь немного отличающийся от уже

    имеющегося, нет необходимости в переписывании заново уже существующего

    кода. Вы объявляете, что новый класс

    tNewClass=class(tOldClass);

    является потомком или дочерним классом класса tOldClass, называемого

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

    свойства.

    В Delphi все классы являются потомками класса tObject. Поэтому, если вы

    строите дочерний класс прямо от tObject, то в определении его можно не

    упоминать. Следующие два описания одинаково верны:

    tMyClass=class(tObject);

    tMyClass=class;

    Более подробно класс tObject будет рассмотрен ниже.

    Унаследованные от класса-предка поля и методы доступны в дочернем классе;

    если имеет место совпадение имен методов, говорят, что они перекрываются.

    Рассмотрим поведение методов при наследовании. По тому, какие действия

    происходят при вызове, методы делятся на три группы. В первую группу

    отнесем статические методы, во вторую - виртуальные (virtual) и

    динамические (dynamic) и, наконец, в третью - появившиеся только в Delphi 4

    перегружаемые (overload) методы.

    Статические методы, а также любые поля в классах-потомках ведут себя

    одинаково: можно без ограничений перекрывать старые имена и при этом менять

    тип методов. Код нового статического метода полностью перекрывает (заменяет

    собой) код старого метода:

    type

    tFirstClass=class

    fData:Extended;

    procedure SetData(aValue:Extended);

    end;

    tSecondClass=class(tFirstClass)

    fData:Integer;

    procedure SetData(aValue:Integer);

    end;

    procedure tFirstClass.SetData(aValue:Extended);

    Begin

    fData:=1.0;

    End;

    procedure tFirstClass.SetData(aValue:Extended);

    Begin

    fData:=1;

    inherited SetData(0.99);

    End;

    В этом примере разные методы с именем SetData присваивают значение разным

    полям с именем fData. Перекрытое (одноименное) поле предка недоступно в

    потомке. Поэтому два одноименных поля с именем fData приведены только для

    примера.

    В отличие от поля, внутри других методов перекрытый метод доступен при

    указании ключевого слова inherited. По умолчанию методы объектов классов

    статические - их адрес определяется еще на этапе компиляции проекта,

    поэтому они вызываются быстрее всего.

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

    Они должны быть объявлены путем добавления соответствующей директивы

    dynamic или virtual. С точки зрения наследования методы этих двух категорий

    одинаковы: они могут быть перекрыты в дочернем классе только одноименными

    методоми, имеющими тот же тип.

    Полиморфизм. Виртуальные и динамические методы

    Рассмотрим следующий пример. Пусть имеется некое обобщенное поле для

    хранения данных - класс tFiled и три его потомка - для хранения строк,

    целых и вещественных чисел:

    type

    tFiled = class

    function GetData:string; virtual; abctract;

    end;

    tStringFiled = class(tFiled)

    fData:string;

    function GetData: string; override;

    end;

    tIntegerFiled = class(tFiled)

    fData:Integer;

    function GetData: string; override;

    end;

    tExtendedFiled = class(tFiled)

    fData:Extended;

    function GetData: string; override;

    end;

    function tStringFiled.GetData: string;

    Begin

    Result:=fData;

    End;

    function tIntegerFiled.GetData: string;

    Begin

    Result:=IntToStr(fData);

    End;

    function tExtendedFiled.GetData: string;

    Begin

    Result:=FloatToStr(fData,ffFixed, 7, 2);

    End;

    function ShowData(aFiled:tFiled): string;

    Begin

    Form1.Label1.Caption:=aFiled.GetData;

    End;

    В этом примере классы содержат разнотипные поля данных fData, а также имеют

    унаследованный от tFiled виртуальный метод GetData, возвращающий данные в

    виде строки. Внешняя по отношению к ним процедура ShowData получает объект

    в виде параметра и показывает эту строку.

    Согласно правилам контроля соответствия типов (typecasting) ObjectPascal,

    объекту, как указателю на экземпляр класса, может быть присвоен адрес

    экземпляра любого из дочерних типов. Это означает, что в предыдущем примере

    в процедуру ShowData можно передавать объекты классов tStringFiled,

    tIntegerFiled, tExtendedFiled и любого другого потомка tFiled.

    Но какой (точнее, чей) метод GetData будет при этом вызван? Тот, который

    соответствует классу фактически переданного объекта. Этот принцип

    называется полиморфизмом.

    Возвращаясь к рассмотренному выше примеру, отметим, что у компилятора нет

    возможности определить класс объекта, фактически переданного в процедуру

    ShowData на этапе компиляции. Механизм, позволяющий определить этот класс

    прямо во время выполнения называется поздним связыванием. Естественно,

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

    таблица виртуальных методов (Virtual Method Table, VMT) и таблица

    динамических методов (Dynamic Method Table, DMT).

    Различие между виртуальными и динамическими методами заключается в

    особенности поиска адреса. Когда компилятор встречает обращение к

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

    адресу код, который обращается к VMT и извлекает оттуда нужный адрес. Такая

    таблица есть для каждого класса. В ней хранятся адреса всех виртуальных

    методов класса, независимо от того, унаследованы ли они от предка или

    перекрыты в данном классе. Отсюда и достоинства и недостатки виртуальных

    методов: они вызываются сравнительно быстро, однако для хранения указателей

    на них в таблице VMT требуется большое количество памяти.

    Динамические методы вызываются медленнее, но позволяют более экономно

    расходовать память. Каждому динамическому методу системой присваивается

    уникальный индекс. В таблице динамических методов класса хранятся индексы

    только тех методов только тех динамических методов, которые описаны в

    данном классе. При вызове динамического метода происходит поиск в этой

    таблице. В случае неудачи просматриваются DMT всех классов-предков в

    порядке их иерархии и, наконец, tObject, где имеется стандартный обработчик

    вызова динамических методов. Экономия памяти очевидна.

    Для перекрытия и виртуальных и динамических методов служит директива

    override, с помощью которой (и только с ней!) можно переопределять оба этих

    типа методов.

    type

    tParentClass=class

    fFirstFiled:Integer;

    fSecondFiled:longInt;

    procedure StaticMethod;

    procedure VirtualMethod1; virtual;

    procedure VirtualMethod2; virtual;

    procedure DynamicMethod1; dynamic;

    procedure DynamicMethod2; dynamic;

    end;

    tChildClass=class(tParentClass)

    procedure StaticMethod;

    procedure VirtualMethod1; override;

    procedure DynamicMethod1; override;

    end;

    Первый метод класса tChildClass создается заново, два остальных

    перекрываются. Создадим объекты этих классов:

    var Obj1: tParentClass;

    Obj2: tChildClass;

    Внутренняя структура этих объектов показана ниже. [pic]

    Первое поле каждого экземпляра каждого объекта содержит указатель на его

    класс. Класс, как структура состоит из двух частей. Начиная с адреса, на

    который ссылается указатель на класс, располагается таблица виртуальных

    методов. Она содержит адреса всех виртуальных методов класса, включая и

    унаследованные от предков. Перед таблицей виртуальных методов расположена

    специальная структура, содержащая дополнительную информацию. В ней

    содержатся данные, полностью характеризующие класс: имя, размер

    экземпляров, указатели на класс-предок и т.д. Одно из полей структуры

    содержит адрес таблицы динамических методов класса (DMT). Таблица имеет

    следующий формат: в начале - слово, содержащее количество элементов

    таблицы. Затем - слова, соответствующие индексам методов. Нумерация

    индексов начинается с –1 и идет по убывающей. После индексов идут

    собственно адреса динамических методов. Следует обратить внимание на то,

    что DMT объекта Obj1 состоит из двух элементов, Obj2 - из одного,

    соответствующего перекрытому методу DynamicMethod1. В случае вызова

    Obj2.DynamicMethod2 индекс не будет найден в DMT Obj2, и произойдет

    обращение к DMT Obj1. Именно так экономится память при использовании

    динамических методов.

    Как указывалось выше, указатель на класс указывает на первый виртуальный

    метод. Служебные данные размещаются перед таблицей виртуальных методов, то

    есть с отрицательным смещением. Эти смещения описаны в модуле SYSTEM.PAS:

    vmtSelfPtr = -76

    vmtIntfTable = -72

    vmtAutoTable = -68

    vmtInitTable = -64

    vmtTypeInfo = -60

    vmtFiledTable = -56

    vmtMethodTable = -52

    vmtDynamicTable = -48

    vmtClassName = -44

    vmtInstanceSize = -40

    vmtParent = -36

    vmtSafeCallException = -32

    vmtAfterConstruction = -28

    vmtBeforeDestruction = -24

    vmtDispatch = -20

    vmtDefaultHandler = -16

    vmtNewInstance = -12

    vmtFreeInstance = -8

    vmtDestroy = -4

    Поля vmtDynamicTable, vmtDispatch и vmtDefaultHandler отвечают за вызов

    динамических методов. Поля vmtNewInstance, vmtFreeInstance и vmtDestroy

    содержат адреса методов создания и уничтожения экземпляров класса. Поля

    vmtIntfTable, vmtAutoTable, vmtSafeCallException введены для обеспечения

    совместимости с моделью объекта COM. Остальные поля доступны через методы

    объекта tObject. В Object Pascal эта информация играет важную роль и может

    использоваться программистом неявно. В языке определены два оператора - is

    и as, неявно обращающиеся к ней. Оператор is предназначен для проверки

    совместимости по присвоению экземпляра объекта с заданным классом.

    Выражение вида:

    AnObject is tObjectType

    Принимает значение True только если объект AnObject совместим по присвоению

    с классом tObjectType, то есть является объектом этого класса или его

    потомком.

    Оператор as введен в язык специально для приведения объектных типов. С его

    помощью можно рассматривать экземпляр объекта как принадлежащий к другому

    совместимому типу:

    with AObjectOfSomeType as tAnotherType do . . .

    От стандартного способа приведения типов использование оператора as

    отличается наличием проверки на совместимость типов во время выполнения:

    попытка приведения к несовместимому типу приводит к возникновению

    исключительной ситуации eInvalidCast. После выполнения оператора as сам

    объект остается неизменным, но выполняются те его методы, которые

    соответствуют присваиваемому классу.

    Вся информация, описывающая класс, создается и размещается в памяти на

    этапе компиляции. Доступ к информации вне методов этого класса можно

    получить, описав соответствующий указатель, называющийся указателем на

    класс или указателем на объектный тип (class reference). Он описывается при

    помощи зарезервированных слов class of. Например, указатель на класс

    tObject описан в модуле SYSTEM.PAS и называется tClass. Аналогичные

    указатели определены и для других важнейших классов: tComponentClass,

    tControlClass и т.д.

    С указателем на класс тесно связано понятие методов класса. Такие методы

    можно вызывать и без создания экземпляра объекта - с указанием имени класса

    в котором они описаны. Перед описанием метода класса нужно поставить

    ключевое слово class.

    Разумеется, методы класса не могут использовать значения, содержащиеся в

    полях класса: ведь экземпляра класса не существует!!! Методы класса служат

    для извлечения внутренней информации класса. Ниже перечислены методы класса

    tObject:

    Метод и Описание

    сlass function ClassName:ShortString

    Возвращает имя класса

    сlass function ClassNameIs(const Name:ShortString):Boolean

    Принимает значение True, если имя класса равно заданному

    сlass function ClassParent:tClass

    Возвращает указатель на родительский класс

    сlass function ClassInfo:pointer

    Возвращает указатель на структуру с дополнительными данными об

    опубликованных методах и свойствах.

    сlass function InstanceSize:Longint

    Возвращает размер экземпляра класса

    сlass function InheritsFrom (aClass: tClass):Boolean

    Возвращает True, если данный класс наследует от заданного

    сlass function MethodAddress(const Name:ShortString):Pointer

    Возвращает адрес метода по его имени (только для опубликованных методов)

    сlass function MethodName (Addres: pointer):ShortString

    Возвращает имя метода по его адресу (только для опубликованных методов)

    В Delphi 4 в класс tObject добавлены еще два виртуальных метода -

    AfterConstruction и BeforeDestruction. Как следует из названия, они

    вызываются сразу после создания экземпляра объекта и непосредственно перед

    уничтожением.

    Перегрузка методов

    В Delphi 4 появилась новая разновидность методов - перегружаемые.

    Перегрузка нужна для того, чтобы произвести одинаковые или похожие действия

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

    словом overload.

    Type

    tFirstClass=class

    E:extended;

    procedure SetData(aValue: Extended); overload;

    end;

    tSecondClass=class(tFirstClass)

    I:integer;

    procedure SetData(aValue: Integer); overload;

    end;

    Объявив метод SetData перегружаемым, в программе можно использовать обе его

    реализации одновременно. Это возможно потому, что компилятор определяет тип

    передаваемого параметра (целый или вещественный) и в зависимости от этого

    подставит вызов соответствующего метода.

    Для перегрузки виртуального метода используется зарезервированное слово

    reintroduce:

    procedure SetData(aValue:string); reintrouce;overload;

    На перегрузку методов накладывается ограничение: нельзя перегружать методы,

    находящиеся в области видимости published.

    Абстрактные методы

    Абстрактными называются методы, которые определены в классе, но не содержат

    никаких действий, никогда не вызываются и обязательно должны быть

    переопределены в классах-потомках. Абстрактными могут быть только

    виртуальные и динамические методы. Для описания абстрактного метода

    используется директива abstract:

    Procedure NeverCallMe; virtual; abstract;

    Никакого кода абстрактный метод не содержит. Его вызов приведет к созданию

    исключительной ситуации eAbstractError.

    События

    Операционная система Windows® основана на сообщениях. Сообщения эти

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

    других программ. Таких сообщений в Windows сотни, и по большому счету,

    написать программу для Windows - значит определить реакцию на некоторые из

    них.

    Работать с таким количеством сообщений, даже имея под рукой справочник,

    нелегко. Поэтому одним из главных преимуществ Delphi является то, что

    программист полностью избавлен от необходимости работать с сообщениями

    Windows (хотя такая возможность у него имеется). Типовых событий в Delphi -

    не более двух десятков, и все они имеют простую интерпретацию, не требующую

    глубоких знаний среды.

    С точки зрения языка, событие - это поле процедурного типа, предназначенное

    для создания пользовательской реакции на те или иные входные воздействия:

    Property OnMyEvent: tMyEvent read FMyEvent write FMyEvent;

    Здесь OnMyEvent - поле объекта, содержащее адрес некоторого метода.

    Страницы: 1, 2, 3, 4, 5, 6, 7


    Приглашения

    09.12.2013 - 16.12.2013

    Международный конкурс хореографического искусства в рамках Международного фестиваля искусств «РОЖДЕСТВЕНСКАЯ АНДОРРА»

    09.12.2013 - 16.12.2013

    Международный конкурс хорового искусства в АНДОРРЕ «РОЖДЕСТВЕНСКАЯ АНДОРРА»




    Copyright © 2012 г.
    При использовании материалов - ссылка на сайт обязательна.