The cast to baseform may have changed to the vmt entry of baseform, not the vmt entry of the derived form.
More likely is that the pointer p isn't initialized.
But since we don't get information about the code and the actual error it's just guessing.
I initially thought putting a class in a classless pointer would loose some information but it doesn't. That also just works (see below).
So it's not an abstract error that's getting thrown here, is my guess. But just an access violation or something else.
program Project1;
type
TAnimal = class
procedure Sound; virtual; abstract;
end;
TCat = class(TAnimal)
procedure Sound; override;
end;
procedure TCat.Sound;
begin
writeln('miauw');
end;
var
animal: TAnimal; // notice the variable is even base class
p: pointer;
begin
animal := TCat.Create; // but we create it as child class
p := animal;
TAnimal(p).Sound; // shows miauw
readln;
end.