Главная    Почта    Новости    Каталог    Одноклассники    Погода    Работа    Игры     Рефераты     Карты
  
по Казнету new!
по каталогу
в рефератах

Программирование на Delphi

st[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,  vmtFreeInsta
12345След.
скачать работу

Программирование на Delphi

 

Отправка СМС бесплатно

На правах рекламы


ZERO.kz
 
Модератор сайта RESURS.KZ