ПЕРЕЛІК ДИСЦИПЛІН:
  • Адміністративне право
  • Арбітражний процес
  • Архітектура
  • Астрологія
  • Астрономія
  • Банківська справа
  • Безпека життєдіяльності
  • Біографії
  • Біологія
  • Біологія і хімія
  • Ботаніка та сільське гос-во
  • Бухгалтерський облік і аудит
  • Валютні відносини
  • Ветеринарія
  • Військова кафедра
  • Географія
  • Геодезія
  • Геологія
  • Етика
  • Держава і право
  • Цивільне право і процес
  • Діловодство
  • Гроші та кредит
  • Природничі науки
  • Журналістика
  • Екологія
  • Видавнича справа та поліграфія
  • Інвестиції
  • Іноземна мова
  • Інформатика
  • Інформатика, програмування
  • Юрист по наследству
  • Історичні особистості
  • Історія
  • Історія техніки
  • Кибернетика
  • Комунікації і зв'язок
  • Комп'ютерні науки
  • Косметологія
  • Короткий зміст творів
  • Криміналістика
  • Кримінологія
  • Криптология
  • Кулінарія
  • Культура і мистецтво
  • Культурологія
  • Російська література
  • Література і російська мова
  • Логіка
  • Логістика
  • Маркетинг
  • Математика
  • Медицина, здоров'я
  • Медичні науки
  • Міжнародне публічне право
  • Міжнародне приватне право
  • Міжнародні відносини
  • Менеджмент
  • Металургія
  • Москвоведение
  • Мовознавство
  • Музика
  • Муніципальне право
  • Податки, оподаткування
  •  
    Бесплатные рефераты
     

     

     

     

     

     

         
     
    Подорожуючи по TObject. Або як воно працює
         

     

    Інформатика, програмування

    Подорожуючи по TObject. Або як воно працює

    Максим Ігнатьєв

    Кожен клас у Delphi є спадкоємцем TObject, і, відповідно, володіє усіма його властивостями і методами. Це, поза сумнівом, корисний факт, але які його методи і властивості, які його основні властивості і як їх можна використовувати? Як ми побачимо трохи пізніше, дуже багато чого в реалізації TObject направлено на опис об'єктної моделі Delphi.

    Розглянемо його опис детальніше.

    TObject class =

    constructor Create;

    procedure Free;

    class function InitInstance (Instance: Pointer): TObject;

    procedure CleanupInstance;

    function ClassType: TClass;

    class function ClassName: ShortString;

    class function ClassNameIs (const Name: string): Boolean;

    class function ClassParent: TClass;

    class function ClassInfo: Pointer;

    class function InstanceSize: Longint;

    class function InheritsFrom (AClass: TClass): Boolean;

    class function MethodAddress (const Name: ShortString): Pointer;

    class function MethodName (Address: Pointer): ShortString;

    function FieldAddress (const Name: ShortString): Pointer;

    function GetInterface (const IID: TGUID; out Obj): Boolean;

    class function GetInterfaceEntry (const IID: TGUID): PInterfaceEntry;

    class function GetInterfaceTable: PInterfaceTable;

    function SafeCallException (ExceptObject: TObject;

    ExceptAddr: Pointer): HResult; virtual;

    procedure AfterConstruction; virtual;

    procedure BeforeDestruction; virtual;

    procedure Dispatch (var Message); virtual;

    procedure DefaultHandler (var Message); virtual;

    class function NewInstance: TObject; virtual;

    procedure FreeInstance; virtual;

    destructor Destroy; virtual;

    end;

    Відразу видно методи класу, а їх функціональність, як відомо, не залежить від факту існування примірника. Розглянемо детальніше кожний з методів.

    Відразу хочу обмовитися, методи - конструктори і деструктори насправді є операторами, то є внутрішніми, що не залежать від їх реалізації в коді, конструкціями.

    Constructor Create;

    Всі об'єкти створюються за допомогою виклику конструктора. Власне конструктор не зобов'язаний називатися Create, просто це прийняте назва даного методу. Конструктор на насправді є методом класу, і в процесі його роботи викликаються такі методи:

    NewInstance

    InitInstance

    Create

    AfterConstruction

    Насправді виклик цих методів відбувається досить цікаво. У TObject конструктор не виконує ніякої діяльності, однак, як кореневої клас ієрархії він створюється на рівні RTM. Що ж відбувається? Після виклику конструктора RTM викликає метод NewInstance, який виділяє область в пам'яті, узгоджуючи при цьому з значенням vmtInstanceSize, яке формується при компіляції. У рамках виклику NewInstance виконується виклик InitInstance, який заповнює поля методу значеннями, позначеними в модифікаторах default, далі виконується код, описаний в тілі процедури Create (або тієї, що заявлена як конструктора), після чого управління передається в точку, визначену в точці vmtAfterConstruction, яка за замовчуванням вказує на метод AfterConstruction. Всі ці маніпуляції дозволяють максимально спростити процес гнучкого створення екземпляра класу в рамках об'єктної моделі Delphi. Таким чином, при створенні екземпляра класу (об'єкта) ви можете «бути присутнім» на будь-якій його фазі. Сенс процедури AfterConstruction полягає в тому, щоб виявити момент закінчення конструювання класу. Зручність його використання полягає в тому, що він викликається тільки при вдалому виконанні конструктора, що, самі розумієте досить вигідно. На сьогоднішній момент тільки TCustomForm і TCustomDataModule перевантажують цей метод спеціально для того, щоб виконати специфічні для них функції, так що заважає нам зробити те ж саме? Але це вже питання конструювання класу.

    Що ж відбудеться при виникненні виняткової ситуації в рамках конструктора? Тут важливо знати про те, що всі елементи класу вже створені і при виникненні виняткової ситуації ми знаємо, що можна видалити. Так от при виникненні виключення викликаються всі дії, пов'язані з руйнуванням -- виклик деструктора, все по повній програмі.

    Важливо знати, що при виклику конструктора класу він викликається як конструктор і створює екземпляр, при виклику ж конструктора в об'єкта він викликається як процедура і нового екземпляра не створює, звідси отримують свій початок помилки наступного роду:

    Var

    O: TObject;

    Begin

    O. Create;// Неправильний виклик

    O: = TObject.Create;// Коректний виклик

    End;

    При виклику методу конструктора в об'єкта важливо відзначити той факт, що якщо в конструкторі створюються поля-об'єкти, то тут виникає потенційна небезпека витоку пам'яті, тому що нові екземпляри створюються, а старі не знищуються.

    Procedure Free;

    Ця процедура ініціює процес руйнування об'єкта в пам'яті. Чому ж не деструктор? Виклик деструктора є коректним звільненням ресурсів для застарілого способу визначення об'єктів object. Якщо ж подивитися на те, яким чином працює ця процедура, то можна побачити дуже цікаву картину.

    procedure TObject.Free;

    asm

    TEST EAX, EAX

    JE @ @ exit

    MOV ECX, [EAX]

    MOV DL, 1

    CALL dword ptr [ECX]. VmtDestroy

    @ @ exit:

    end;

    Що ж ми бачимо? У першому рядку відбувається звірка покажчика на Self (себе) з нулем - а не звільнили чи нас вже? Якщо ще ні, то відповідно вказівником на vmtDestroy ми викликаємо реальний деструктор. В іншому випадку відбувається вихід з процедури. Таким чином відбувається тривіальна "перевірка на дурня» з боку RTM Delphi. Коли Ви робите ж деструктора ми безпосередньо звільняємо (або не звільняємо, а даремно) ресурси об'єкта. Знову ж таки при звільненні ресурсів виконується повний набір дій.

    BeforeDestruction

    FreeInstance

    Метод FreeInstance викликає каскад процедур, спрямованих на звільнення всіх захоплених ресурсів, у тому числі і динамічних масивів, Variant типів і багато чого іншого. Це має бути корисно при виникненні виняткових ситуаціях в конструкторі при вже створених внутрішніх динамічних структурах. Це також дуже корисно як механізм збору сміття всередині об'єкта.

    class function InitInstance (Instance: Pointer): TObject;

    Функція ініціалізації екземпляра інформацією з VMT, при цьому враховується використання інтерфейсів при спадкуванні. Важливо звернути увагу на те, що це функція класу, фактично ця функція заповнює болванку об'єкта, створену функцією NewInstance.

    Procedure CleanupInstance;

    Процедура повернення примірника до «невинному» змісту. При цьому використовуються інформація, що зберігається в vmtInitTable і в vmtParent.

    Function ClassType: TClass;

    Повертає клас об'єкта. А якщо бути більш точним, то повертається безпосередньо покажчик на VMT.

    class function ClassName: ShortString;

    Повертає назва класу. Використовується VMT.

    class function ClassNameIs (const Name: string): Boolean;

    Виконує звірку назви з назвою потрібного класу. Використовується при виконанні оператора is.

    class function ClassParent: TClass;

    Віддає вказівник на батьківський клас. Використовується при виконанні оператора is.

    class function ClassInfo: Pointer;

    Повертає покажчик на RTTI інформацію про клас. Якщо клас скомпільований без використання директиви $ M +, то повертається nil.

    class function InstanceSize: Longint;

    Розмір екземпляра. Як видно з опису інформація про розмір і про RTTI зберігається в VMT поза прив'язкою до конкретного екземпляру. Судячи з усього, ця інформація формується під час компіляції.

    class function InheritsFrom (AClass: TClass): Boolean;

    Повертає точна вказівка на те, що даний клас успадкований від шуканого. Ця функція сканує VMT і батьків цього VMT на відповідність зазначеного класу.

    class function MethodAddress (const Name: ShortString): Pointer;

    Сканує VMT на наявність методу і при вдалому результаті повертає вказівник але нього. При не знаходженні методу в "рідний" VMT сканується VMT батька і так до тих пір, поки не буде знайдений (або не знайдено) адреса методу. Таким чином здійснюється реалізація метаморфізму в об'єктної моделі Delphi.

    class function MethodName (Address: Pointer): ShortString;

    Функція обернено попередньої.

    Function FieldAddress (const Name: ShortString): Pointer;

    Доступ до полів. Повертає вказівник на поле. Як завжди використовує VMT.

    Function GetInterface (const IID: TGUID; out Obj): Boolean;

    Використовується при спадкуванні інтерфейсів і повертає інтерфейс зазначених вище IID.

    class function GetInterfaceEntry (const IID: TGUID): PinterfaceEntry;

    Повертає точку входу інтерфейсу на вказаний IID.

    class function GetInterfaceTable: PInterfaceTable;

    Таблиця інтерфейсів. Незважаючи на те, що заявлено використання нескінченного числа інтерфейсів, у вихідному тексті ясно вказано на 10000 елементів таблиці інтерфейсів. Я, зрозуміло, не хочу поставити експеримент і спробувати перевищити цей ліміт, але прогрес йде такими темпами, що, боюся, через деякий час цей ліміт буде вичерпано.

    Function SafeCallException (ExceptObject: TObject; ExceptAddr: Pointer): HResult; virtual;

    Безпечна обробка переривання, однак, використання цього методу безпосередньо в TObject поверне Вам E_UNEXPECTED, то є щось несподіване. Викликається кожен разу при виникненні виключення всередині коду об'єкта з вказівкою на об'єкт винятки та адреса, що викликав виняток.

    Procedure AfterConstruction; virtual;

    Процедура, викликається після створення екземпляра. Виклик процедури здійснюється за адресою, прописаному в VMT. Прямий виклик ніде не прописаний, судячи з усього, ця можливість прописана в RTM, де вказані всі виклики.

    Procedure BeforeDestruction; virtual;

    Процедура, викликається до руйнування об'єкта.

    Procedure Dispatch (var Message); virtual;

    Внаслідок використання Windows у якості базової платформи розробники вирішили не проходити мимо основного способу обробки межоб'ектного взаємодії -- системи повідомлень. Цей спосіб якраз і реалізується цим методом. Вельми розумно було помістити його саме в TObject, адже він є базовим для всіх класів, визначених в рамках об'єктної моделі Delphi. Цей метод сканує VMT на наявність обробника повідомлення, ID якого зазначений у перших 4 байтах (довге слово, Cardinal) параметра Message і якщо не знаходить, то викликає DefaultHandler. Тобто можна відловлювати події, що відбуваються не тільки у елементів управління, а й у класів нижчої ієрархії.

    Procedure DefaultHandler (var Message); virtual;

    Оброблювач подій за замовчуванням. Викликається методом Dispatch при не знаходженні методу-обробника відповідного повідомлення.

    class function NewInstance: TObject; virtual;

    Створює екземпляр класу. Розумно скористатися цією функцією для клонування об'єктів, тому що, не знаючи початкового класу, можна створювати нові екземпляри вже готових об'єктів без використання RTTI.

    procedure FreeInstance; virtual;

    Звільняє ресурси примірника. Використання цього методу не вітається через його тісному взаємозв'язку з VMT, тобто перевантаження цього методу повинна проводитися з великою обережністю. Виклик ж методу безпосередньо в сукупності з InitInstance може служити для того, щоб створити екземпляр «у собі», адже деякі завдання вимагають відкату стану об'єкта на момент створення.

    destructor Destroy; virtual;

    Власне деструктор. Викликається методом Free після посвідчення в тому, що примірник поки існує. Є одне зауваження з приводу іменування деструктора - він повинен називатися Destroy, це пов'язано з його віртуальністю, а відповідно і перевантаженням. Якщо Ви назвете деструктор іншим ім'ям, то при спробі викликати успадкований метод RTM не знайде опис методу з вашим ім'ям, а це потягне за собою порушення функціональності процедури руйнування об'єкта. Проте цікаво відзначити одну деталь. Наявність виклику успадкованого деструктора не обов'язково, хоча і бажано - адже не всі розробники люблять обробляти події часу виконання, а звільнення пам'яті, відведеної під примірник, відбудеться без участі коду, описаного в деструктор.

    Даючи опис методам базового класу TObject, я намагався дати уявлення про об'єктної моделі Delphi, про життєвому циклі об'єкта, про методи використання об'єктів в власних програмах та правила перевантаження. Як видно з вищесказаного основою для роботи з екземплярами є VMT, і використання RTTI не завжди необхідно для виконання деяких специфічних операцій з екземпляром. Використання ж RTTI, на мій погляд, не завжди виправдовується, однак при написанні RunTime редакторів компонент це засіб досить зручно.

    У результаті вивчення вихідного коду виявився цікавий момент - при виклику будь-якого методу в EAX знаходиться покажчик ... на VMT! Чи не це є явним вказівкою на об'єктну орієнтованість Delphi?! Вивчаючи матеріали книги "Delphi in nutshell "Рея Лішнера (Ray Lischner) я наткнувся на цікавий факт -- таблицю порівняння об'єктних моделей деяких мов, дозволю собі навести її з деяким перекладом і доповненнями:

    Підтримувані можливості об'єктних моделей деяких мов програмування.                      

    Можливість               

    Delphi                              

    Java               

    Visual     Basic                       

    Спадкування               

    +               

    +               

    +                                      

    Множинне спадкування                              

    +                                                     

    Інтерфейси               

    +               

    Як чисто абстрактні класи               

    +               

    +                       

    Один базовий клас               

    +                              

    +                                      

    Метакласси               

    +                              

    +                                      

    Статичні поля класів               

    Як поля модуля               

    +               

    +                                      

    Віртуальні методи               

    +               

    +               

    +                                      

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

    +               

    +               

    +                                      

    Статичні методи класів               

    +               

    +               

    +                                      

    Динамічні методи               

    +                                                                    

    Збір сміття               

    Інтерфейсні методи і динамічні     деструктори                              

    +               

    Інтерфейсні методи                       

    Типи Variant               

    +                                             

    +                       

    OLE automation               

    +                                             

    +                       

    Статичний контроль типів               

    +               

    +               

    +                                      

    Обробка винятків               

    +               

    +               

    +               

    +                       

    Перевантаження методів               

    +               

    +               

    +                                      

    поліморфні виклики               

    +                              

    +                                      

    Перевантаження операторів                              

    +                                                     

    Методи - не члени класу               

    +               

    +                              

    +                       

    Змінні - не члени об'єкта               

    +               

    +                              

    +                       

    Властивості               

    +                                             

    +                       

    RTTI               

    +               

    Тільки для операторів is і     as               

    +                                      

    Загальні типи (шаблони)                              

    +                                                     

    Підтримка ниток               

    +                              

    +                                      

    Обробка повідомлень               

    +                                                                    

    Вбудований асемблер               

    +               

    У деяких реалізаціях               

    +                                      

    Inline функції                              

    +                                                     

    Пакети               

    +                              

    +                                      

    Друзі класу               

    Модульна видимість               

    +               

    Пакетна видимість                                   

    Тут видно деякі особливості, які не є очевидними на перший погляд. Що ж таке динамічні методи? Відразу варто зробити застереження - це модифікатор способу виклику методу, і з цього його відразу треба поставити в один ряд з іншими способами виклику методів - статичними, віртуальними і репредставітельнимі. Чим же вони відрізняються і коли вони потрібні?

    Статичні методи (їхній аналог в Java - final, фінальні) є не перевантажує методами, їх функціональність остаточна, наприклад конструктор Create класу TObject - він порожній і ніякої додаткової діяльності не несе, з цього виклик цього методу не поліморфа. З цього, якщо ви хочете перевантажити статичний метод, то Вам доведеться заново описувати всю його функціональність.

    Віртуальні методи це методи, які дозволяють формувати ланцюжки поліморфних викликів за допомогою статичного зв'язування через таблицю віртуальних методів VMT. Це виглядає приблизно так:                      

    Метод          

    Посилання                       

    DoOne               

    Self.DoOne                       

    DoTwo               

    Self.Parent.DoTwo                       

    DoThree                    

    Self.Parent.Parent.DoThree                    

    Щоб бути цілком точним, треба сказати, що в таблиці вказані всі віртуальні методи, визначені в батьках плюс всередині самого класу. Якщо є перевантажені методи, то в таблиці на відповідних місцях ставляться вхідні точки нових методів, якщо ж ні - то вхідні точки методів батьків. Таким чином, можна точно сказати, який метод треба викликати при зверненні до таблиці віртуальних методів.

    Динамічні методи зберігають точки входу в спеціальній таблиці динамічних методів, ця таблиця будується тільки для змінених або доданих методів. Таким чином зберігатися менше інформації про клас, але виклик методів відбувається довше, внаслідок лінійного пошуку методу в таблиці динамічних методів класу і його батьків, на що витрачається деякий час.

    Репредствавітельние методи це методи, функціональність яких перевизначено повністю щодо батьків. Взагалі-то вказівка директиви reintroduce не обов'язково, але це позбавить Вас від зайвого попередження про перевантаження методу з боку компілятора.

    Ще один цікава особливість TObject - Це зберігання на рівні VMT інформації про три методи з цікавою назвою: QueryInterface, AddRef і Release. Тобто будь-який клас, створений в рамках об'єктної моделі COM Delphi є об'єктом! Єдиним обмеженням тут є те, що для функціонування цих методів необхідно успадкувати хоча б один інтерфейс, що і зроблено в рамках іншого базового класу TInterfacedObject.

    Увага! Забороняється передрук цієї статті або її частини без узгодження з автором. Якщо ви хочете розмістити цю статтю на своєму сайті або видати в друкованому вигляді, зв'яжіться з автором.

    Список літератури

    Для підготовки даної роботи були використані матеріали з сайту http://coderpro.fatal.ru/

         
     
         
    Реферат Банк
     
    Рефераты
     
    Бесплатные рефераты
     

     

     

     

     

     

     

     
     
     
      Все права защищены. Reff.net.ua - українські реферати ! DMCA.com Protection Status