Полезное для программистов:

Фриланс
Новости
Статьи
   
Рубрики:


Как явно вызвать виртуальный метод дедушки?

Поиск:
Проблема в следующем. Допустим, есть иерархия классов, у которых перекрывается один и тот же виртуальный (или динамический - не важно) метод и в одной из реализаций этого метода вы хотите вызвать виртуальный метод предка своего предка. Новая объектная модель Delphi допускает только вызов методов предка (с помощью ключевого слова inherited) либо вызов методов класса с префиксом - типом класса (например, TLevel1.ClassName).

Эта проблема стандартными средствами не решается. Но сделать требуемый вызов можно. Причем способом, показанным ниже, можно вызвать любой метод для любого класса, однако, в этом случае вся ответственность за правильность работы с методами и полями ложится на программиста. Ниже в методе VirtualFunction класса TLevel3 вызывается метод класса TLevel1, а в функции Level1Always всегда вызывается метод класса TLevel1 для любого его наследника.
Код

TLevel1 = class(TComponent)
  public
    function VirtualFunction: string; virtual;
  end;

  TLevel2 = class(TLevel1)
  public
    function VirtualFunction: string; override;
  end;

  TLevel3 = class(TLevel2)
  public
    function VirtualFunction: string; override;
  end;

  function Level1Always(MyLevel: TLevel1): string;

implementation

  type
    PClass = ^TClass;

  function TLevel1.VirtualFunction: string;
  begin
    Result := 'Level1';
  end;

  function TLevel2.VirtualFunction: string;
  begin
    Result := inherited VirtualFunction+' Level2';
  end;

  function TLevel3.VirtualFunction: string;
  var
    ClassOld: TClass;
  begin
        ClassOld := PClass(Self)^;
    PClass(Self)^ := TLevel1;
    Result := VirtualFunction + ' Level3';
    PClass(Self)^ := ClassOld;
  end;

  function Level1Always(MyObject: TObject): string;
  var
    ClassOld: TClass;
  begin
    ClassOld := PClass(MyObject)^;
    PClass(MyObject)^ := TLevel1;
    Result := (MyObject as TLevel1).VirtualFunction;
    PClass(MyObject)^ := ClassOld;
  end;


Как же это работает? Стандартные так называемые объектные типы (object types - class of ...) на самом деле представляют из себя указатель на VMT (Virtual Method Table) - таблицу виртуальных методов, который (указатель) лежит по смещению 0 в экземпляре класса. Воспользовавшись этим, мы сначала сохраняем 'старый тип класса' - указатель на VMT, присваиваем ему указатель на VMT нужного класса, делаем вызов и восстанавливаем все как было. Причем нигде не требуется, чтобы один из этих классов был бы порожден от другого, т.е. функция Level1Always вызовет требуемый метод вообще для любого экземпляра любого класса.

Если в функции Level1Always сделать попробовать вызов

Код

 Result := MyObject.VirtualFunction;


то будет ошибка на стации компиляции, так как у класса TObject нет метода VirtualFunction. Другой вызов

Код

 Result := (MyObject as TLevel3).VirtualFunction;


будет пропущен компилятором, но вызовет Run-time ошибку, даже если передается экземпляр класса TLevel3 или один из его потомком, так как информация о типе объекта меняется. Динамически распределяемые (dynamic) методы можно вызывать точно таким же образом, т.к. информация о них тоже хранится в VMT. Статические методы объектов вызываются гораздо более простым способом, например

Код

var
    MyLevel3: TLevel3;
  ...
    (MyLevel3 as TLevel1).SomeMethode;


вызовет метод класса TLevel1 даже если у MyLevel3 есть свой такой же метод.
Автор: Epsylon Technologies






Просмотров: 2614

 

 

Новые статьи:


Популярные:
  1. Как сделать цикличным проигрывание MIDI-файла?
  2. Создание AVI файла из рисунков
  3. Как устройство "отключить в данной конфигурации"?
  4. Kто в данный момент присоединен через Сеть?
  5. Как узнать количество доступной памяти?
  6. Как реализовать в RichEdit разноцветный текст?
  7. Как скрыть свое приложение от ProcessViewer
  8. Как программно нажать/скрыть/показ кнопку "Start"?
  9. Модуль работы с ресурсами в PE файлах
10. Функции вызова диалоговых окон выбора
11. Проверка граматики средствами Word'а из Delphi.
12. Модуль для упрощенного вызова сообщений
13. Функции для записи и чтение своих данных в, ЕХЕ- файле
14. Рекурсивный просмотр директорий
15. Network Traffic Monitor
16. Разные модули
17. Универсальная функция для обращения к любым экспортируем функциям DLL
18. Библиотека от VladS
19. Протектор для UPX'а
20. Еще об ICQ, сообщения по контакт листу?
21. Использование открытых интерфейсов
22. Теория и практика использования RTTI
23. Работа с TApplication
24. Примеры использования Drag and Drop для различных визуальных компонентов
25. Что такое порт? Правила для работы с портами
26. Симфония на клавиатуре
27. Загрузка DLL
28. Исправление автоинкремента
29. Взаимодействие с чужими окнами
30. Проверить дубляжи в столбце


 

 

 
 
На главную