目标Pascal - 你如何确保在作为祖先施放时调用后代的方法?

时间:2014-01-09 13:46:52

标签: delphi oop inheritance freepascal

我正在创建一个小型RPG引擎。我刚刚开始为游戏的对象实现一个类树,我不能100%确定我应该在哪里以及在什么情况下使用哪些方法指令。

我查看过Free Pascal Complier的参考指南和其他各种互联网资源,但我仍然不自信。

我计划实现游戏对象处理的方式要求游戏对象的类别有一个共同的基类,并存储在该类的数组中,从而将它们作为祖先投射。

我主要需要了解的是如何确保当我将一个类转换为其中一个祖先时,它调用实际类的重载/重写/重新引入的方法而不是祖先的方法。

谢谢你的时间!

如果我不够清楚,我很乐意在这里澄清/重新说一句。

1 个答案:

答案 0 :(得分:4)

当你将它们放入父类的数组中时,你不会“投射”,你不应该这样做;这不是继承和多态如何工作。

您在父级(祖先)中创建一个虚方法,然后每个子级继承父级的方法并使用自己的特定行为覆盖它。当您调用父方法时,多态性可确保调用正确的方法。

这是一个快速(微不足道)的例子,说明应该如何构建这样的东西。它是控制台应用程序的形式,因此您可以实际运行它以查看输出。

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.

您可以在docwiki找到有关Delphi实施OOP的相当完整的讨论。虽然它不是FreePascal,但大部分都是兼容的,所以它应该有点等同。我不知道任何类似FPC的文档。