Или даже так, «Pure Pascal» версия :)
- Код: Выделить всё
 type
  PPetBehaviour = ^TPetBehaviour;
  TPet = object
    Name: AnsiString;
    Behaviour: PPetBehaviour;
    constructor Init(const _Name: AnsiString);
    procedure TellAboutYourSelf; inline;
  end;
  TPetBehaviour = record
    TellAboutYourSelf: procedure (const Pet: TPet);
  end;
constructor TPet.Init(const _Name: AnsiString);
begin
  Name := _Name;
end;
procedure TPet.TellAboutYourSelf;
begin
  Behaviour^.TellAboutYourSelf(Self);
end;
procedure TCat_TellAbout(const Pet: TPet); // TCat implementation part
begin
  Writeln('Я кот по имени ', Pet.Name, '.');
end;
procedure TDog_TellAbout(const Pet: TPet); // TDog implementation part
begin
  Writeln('Я ', Pet.Name, ', гав-гав!');
end;
const
  TCat: TPetBehaviour = ( // declaration of TCat
    TellAboutYourSelf: @TCat_TellAbout
  );
  TDog: TPetBehaviour = ( // declaration of TDog
    TellAboutYourSelf: @TDog_TellAbout
  );
// using
var
  Pet: TPet;
begin
  Pet.Init('Бусик');
  Pet.Behaviour := @TCat;
  Pet.TellAboutYourSelf;
  Pet.Behaviour := @TDog;
  Pet.TellAboutYourSelf;
end.
Что лично мне не нравится в подобных подходах:
1. Каждый «виртуальный» метод нужно реализовывать через явный параметр объекта (Animal), поля и методы не видны сами по себе.
2. Не вполне понятно как правильно объявить protected-поля в TAnimal, чтобы только потомки TTellAbout их видели.
object не привносит сам по себе что-то новое функционально (всё можно реализовать самостоятельно через ссылки на функции), но даёт некий синтаксический сахар и хотелось бы сохранить по-максимуму наглядность реализации конкретный классов.
Это я выступаю в защиту параметризации конструктора, а не смены поведения на лету (что действительно лучше реализовывать самостоятельно, а не хакать vmt).