Delphi 目标Pascal-如何确保调用Decentant';当转换为acestor时,使用什么方法?
我目前正在创建一个小型RPG引擎。我刚刚开始为游戏的对象实现一个类树,但我不能100%确定我应该在哪里以及在什么情况下使用哪些方法指令 我已经看过免费的Pascal Complier参考指南和其他各种互联网资源,但我仍然没有信心 我计划实现游戏对象处理的方式要求游戏对象的类别有一个公共基类,并将存储在该类的数组中,从而将它们转换为祖先 我主要需要了解的是,当我调用作为其祖先之一的类强制转换时,如何确保它调用实际类的重载/重写/重新引入方法,而不是祖先的方法 谢谢你的时间 如果我不够清楚的话,我很乐意在这里澄清/重述任何事情。当你将他们放入父类数组时,你不是在“铸造”,你不应该这样;这不是继承和多态的工作方式 您在父级(祖先)中创建一个虚拟方法,然后每个子级继承父级的方法,并用它们自己的特定行为覆盖它。当调用父方法时,多态性确保调用正确的方法 下面是一个简单的例子,说明应该如何构造这样的东西。它以控制台应用程序的形式出现,因此您可以实际运行它以查看输出Delphi 目标Pascal-如何确保调用Decentant';当转换为acestor时,使用什么方法?,delphi,oop,inheritance,freepascal,Delphi,Oop,Inheritance,Freepascal,我目前正在创建一个小型RPG引擎。我刚刚开始为游戏的对象实现一个类树,但我不能100%确定我应该在哪里以及在什么情况下使用哪些方法指令 我已经看过免费的Pascal Complier参考指南和其他各种互联网资源,但我仍然没有信心 我计划实现游戏对象处理的方式要求游戏对象的类别有一个公共基类,并将存储在该类的数组中,从而将它们转换为祖先 我主要需要了解的是,当我调用作为其祖先之一的类强制转换时,如何确保它调用实际类的重载/重写/重新引入方法,而不是祖先的方法 谢谢你的时间 如果我不够清楚的话,我很
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
// Base class
TAnimal=class
procedure Sit; virtual; // Virtual keyword *necessary* for things to work
procedure Speak; virtual;
end;
// Descendent classes
TDog=class(TAnimal)
procedure Sit; override; // Override keyword required here
procedure Speak; override;
end;
TCat=class(TAnimal)
// No implementation of Sit, because cats don't sit on command
procedure Speak; override; // Override required here also
end;
// Array type to hold them, so we don't have to typecast anything
TAnimalArray = array of TAnimal;
// Implementation of classes
{ TAnimal }
procedure TAnimal.Sit;
begin
end;
procedure TAnimal.Speak;
begin
// Parent does nothing
end;
{ TCat }
procedure TCat.Speak;
begin
inherited;
WriteLn('Meow.');
end;
{ TDog }
procedure TDog.Sit;
begin
inherited;
WriteLn('Sitting down now.');
end;
procedure TDog.Speak;
begin
inherited;
Writeln('Woof! Woof!');
end;
// Test code to demonstrate use of inheritance and polymorphism
var
Animals: TAnimalArray;
i: Integer;
Pet: TAnimal; // Variable that holds parent type (TAnimal)
const
NumberOfAnimals = 5;
begin
SetLength(Animals, NumberOfAnimals);
// Fill array with a mix of both dogs and cats
for i := 0 to High(Animals) do
begin
if Odd(i) then
Animals[i] := TDog.Create
else
Animals[i] := TCat.Create;
end;
// Loop to use each one regardless of which type, by just accessing the
// virtual Speak method they overrode from their parent class
for Pet in Animals do
begin
Pet.Speak;
Pet.Sit; // Call method only defined for TDog
end;
WriteLn(''); // Blank line in console to separate loops.
// If FreePascal doesn't support the enumeration (for..in) method, do it
// using a counter:
for i := 0 to High(Animals) do
begin
Animals[i].Speak;
Animals[i].Sit; // Call method only defined for TDog
end;
// In real life code, you'd loop through the array and free each one here.
// In this test code, we're exiting right away, and there's really no point
Readln;
end.
上述操作产生输出:
Meow.
Woof! Woof!
Sitting down.
Meow.
Woof! Woof!
Sitting down.
Meow.
Meow.
Woof! Woof!
Sitting down.
Meow.
Woof! Woof!
Sitting down.
Meow.
您可以在网站上找到关于Delphi的OOP实现的相当完整的讨论。虽然它不是FreePascal,但大部分都是兼容的,因此它应该在某种程度上是等效的。我不知道有任何类似FPC的文档。当您将它们放入父类的数组中时,您不是在“强制转换”,您不应该这样做;这不是继承和多态的工作方式
您在父级(祖先)中创建一个虚拟方法,然后每个子级继承父级的方法,并用它们自己的特定行为覆盖它。当调用父方法时,多态性确保调用正确的方法
下面是一个简单的例子,说明应该如何构造这样的东西。它以控制台应用程序的形式出现,因此您可以实际运行它以查看输出
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
// Base class
TAnimal=class
procedure Sit; virtual; // Virtual keyword *necessary* for things to work
procedure Speak; virtual;
end;
// Descendent classes
TDog=class(TAnimal)
procedure Sit; override; // Override keyword required here
procedure Speak; override;
end;
TCat=class(TAnimal)
// No implementation of Sit, because cats don't sit on command
procedure Speak; override; // Override required here also
end;
// Array type to hold them, so we don't have to typecast anything
TAnimalArray = array of TAnimal;
// Implementation of classes
{ TAnimal }
procedure TAnimal.Sit;
begin
end;
procedure TAnimal.Speak;
begin
// Parent does nothing
end;
{ TCat }
procedure TCat.Speak;
begin
inherited;
WriteLn('Meow.');
end;
{ TDog }
procedure TDog.Sit;
begin
inherited;
WriteLn('Sitting down now.');
end;
procedure TDog.Speak;
begin
inherited;
Writeln('Woof! Woof!');
end;
// Test code to demonstrate use of inheritance and polymorphism
var
Animals: TAnimalArray;
i: Integer;
Pet: TAnimal; // Variable that holds parent type (TAnimal)
const
NumberOfAnimals = 5;
begin
SetLength(Animals, NumberOfAnimals);
// Fill array with a mix of both dogs and cats
for i := 0 to High(Animals) do
begin
if Odd(i) then
Animals[i] := TDog.Create
else
Animals[i] := TCat.Create;
end;
// Loop to use each one regardless of which type, by just accessing the
// virtual Speak method they overrode from their parent class
for Pet in Animals do
begin
Pet.Speak;
Pet.Sit; // Call method only defined for TDog
end;
WriteLn(''); // Blank line in console to separate loops.
// If FreePascal doesn't support the enumeration (for..in) method, do it
// using a counter:
for i := 0 to High(Animals) do
begin
Animals[i].Speak;
Animals[i].Sit; // Call method only defined for TDog
end;
// In real life code, you'd loop through the array and free each one here.
// In this test code, we're exiting right away, and there's really no point
Readln;
end.
上述操作产生输出:
Meow.
Woof! Woof!
Sitting down.
Meow.
Woof! Woof!
Sitting down.
Meow.
Meow.
Woof! Woof!
Sitting down.
Meow.
Woof! Woof!
Sitting down.
Meow.
您可以在网站上找到关于Delphi的OOP实现的相当完整的讨论。虽然它不是FreePascal,但大部分都是兼容的,因此它应该在某种程度上是等效的。我不知道FPC有任何类似的文档。啊,我明白了。我不知道在一个祖先类中存储后代类并不涉及强制转换,我只是假设它是在后台完成的,现在想想它更有意义。这个例子完美地说明了我需要做什么,非常感谢!那么,您将如何调用由后代实现的方法呢?例如,如果说班上的狗实现了一个新的程序,称为“Sit”,那么可以称之为“Sit”吗?当然可以。它将以完全相同的方式工作。正如您所说的,在父级中声明它,在TDog类中提供一个有效的实现。如果你叫它时差,狗就坐着。如果在TCat上调用它,则会调用不执行任何操作的父实现。我会很快添加它,这样你就可以看到两者。我的意思是,如果不在父级中实现它,因为我的游戏中的继承树会有点大,那么在每个类中实现每个过程是很不实际的。比如说,我让更多的动物继承了TAnimal,每个动物都有一个或多个自己独有的过程。当然,你可以这样做,但是你必须知道你要处理的是什么类,并将类型转换为正确的类型。你不能只说“动物。游泳”而在父母那里根本不存在;你必须知道动物是一只
TPolarBear
(或者先用“如果动物是TPolarBear那么”进行测试,然后用TPolarBear(动物)。而不是游泳(这首先破坏了遗传和多态性的全部目的).好的,非常感谢。你已经把事情说得更清楚了,希望我能想出一个更好的方法来实现这个系统。啊,我明白了。我不知道在祖先类中存储后代类不需要强制转换,我只是假设它是在后台完成的,现在想想它更有意义。示例说明我需要完美地完成的事情,非常感谢!那么您将如何调用由后代实现的方法呢?例如,假设类dog实现了一个名为“Sit”的新过程,是否可以调用它?是的,当然。它的工作方式完全相同。正如您所说的,在父级中声明它,在TDog类中提供一个工作实现。如果您在TDog上调用它,狗就坐。如果您在TCat上调用它,则会调用do nothing父级实现。我会很快添加它,以便您可以看到两者.我的意思是,如果不在父类中实现它,因为我游戏中的继承树会有点大,在每个类中实现每个过程是不现实的。比如说,我让更多的动物从TAnimal继承,每个动物都有一个或多个自己独有的过程。当然,你可以这样做,但是你必须知道你要处理的是什么类,并将其类型转换为正确的类型。你不能只对父类中不存在的方法说“Animal.Swim”;你必须知道该动物是TPolarBear
(或者先用“如果动物是TPolarBear”,然后用TPolarBear(Animal.Swim
)(这首先破坏了遗传和多态性的整体目的)