【问题标题】:Inheritance/polymorphism concept继承/多态概念
【发布时间】:2014-04-28 18:58:46
【问题描述】:

我有两个包含相似类型数据的二进制文件,因此我想为这两个文件创建一个统一查看器 (TViewer)。 有些方法对于这两种文件类型是通用的,有些则不是。所以我创建了一个基类 TShape,以及由此而来的 TCircle 和 TTriangle。

伪代码:

TShape = class(TObject)
  function NoOfItems: integer; virtual; abstract; 
end;

TCircle = class(TShape)
  function NoOfItems: integer; override;     <---- The real implementation 
end;

TTriangle = class(TShape)
  function NoOfItems: integer; override;        <---- The real implementation 
end;

TViewer = class(TStringGrid)
  Container: TShape;
end;

我是这样使用它的:

Procedure Main;
begin
 if FileType= Circle 
 then (Viewer.Container as TCircle).Load(FileName)
 else (Viewer.Container as TTriangle).Load(FileName);

 Caption:= Viewer.Container.NoOfItems;  <---- it calls TShape which is abstract
end;

当我这样做时,它会起作用:

if Viewer.Container is TTriangle 
then Caption:= (Viewer.Container as TTriangle).NoOfItems
else ...

但我想直接这样做:

Caption:= Viewer.Container.NoOfItems;

显然,使用is 并没有什么问题,只是我必须在很多地方(几乎无处不在)使用它。有更好的方法来实现这个统一的查看器吗?

更新:

其实也可能是性能问题。我的文件包含非常多的项目(多达数十亿),因此执行如此多的“原样”测试实际上可能会对速度产生真正的影响。

【问题讨论】:

  • 当然,你可以使用IntVar := Viewer.Container.NoOfItems;——这是典型的多态用法
  • 您根本不必对它进行类型转换(并且不要使用示例中的代码),这意味着这很可能不是您的真实代码。 (实际上,这个不可能是你真正的代码,因为你已经将NoOfItems声明为一个返回integer的函数,但是你直接将它分配给Caption。)发布真正的代码如果你需要帮助。
  • @MBo - 它将调用 TShape 的方法。什么都不做(抽象的)。
  • @KenWhite - 是的。这不是真正的代码。真正的代码非常大,可以在这里发布。我将尝试制作一个小的 COMPILABLE 演示。无论如何,Viewer.Container.NoOfItems 调用了 TShape 的方法,它什么也不返回!
  • 好的。我在 TShape 中添加了 Abstract。现在显然 Viewer.Container.NoOfItems 失败了。

标签: delphi oop


【解决方案1】:

你做错了。

您需要更改您的代码,以便在您知道它需要是什么类型之前不会创建容器,然后创建正确的类型:

Procedure Main;
begin

 if FileType= Circle then
   Viewer.Container := TCircle.Create
 else
  Viewer.Container := TTriangle.Create;

 Viewer.Container.Load(FileName);

 Caption := IntToStr(Viewer.Container.NoOfItems);  <---- it calls proper code
end;

这是一个为您使用继承和多态的工作示例:

program InheritancePolymorphismTest;

uses
  System.SysUtils;

type
  TAnimal=class
  public
    procedure Sit; virtual;
    procedure Speak; virtual;
  end;

  TDog=class(TAnimal)
  public
    procedure Sit; override;
    procedure Speak; override;
  end;

  TCat=class(TAnimal)
  public
    procedure Speak; override;
  end;

  TAnimalArray = array of TAnimal;

{ TCat }

procedure TCat.Speak;
begin
  inherited;
  WriteLn('Bah! No way cats speak when told.');
end;

{ TDog }

procedure TDog.Sit;
begin
  inherited;
  WriteLn('Sitting down.');
end;

procedure TDog.Speak;
begin
  inherited;
  Writeln('Woof! Woof!');
end;

procedure TAnimal.Sit;
begin

end;

procedure TAnimal.Speak;
begin

end;


var
  Animals: TAnimalArray;
  i: Integer;
  Pet: TAnimal;
{ TAnimal }

const
  NumAnimals = 5;


begin
  SetLength(Animals, NumAnimals);
  for i := 0 to High(Animals) do
  begin
    if Odd(i) then
      Animals[i] := TDog.Create
    else
      Animals[i] := TCat.Create;
  end;

  for Pet in Animals do
  begin
    Pet.Speak;
    Pet.Sit;
  end;

  Writeln('');
  Readln;
end.

【讨论】:

  • "在你知道它需要什么类型之前,不会创建容器" 是的......对......显然。我不知道我是怎么搞砸的。非常感谢!!!! +1 并被接受。
  • 我会考虑使用工厂模式来决定要创建什么。 If FillType = Circle Then... 有点臭。
  • @Andy_D:问题不在于使用什么设计模式。这是“为什么继承和多态在这里不起作用?”,这就是我的回答。不过,感谢您的意见。 :-)
  • 我知道@KenWhite,我只是观察到工厂模式将使解决方案更加灵活和可读。 :)
【解决方案2】:

真实代码和真实输出。多态性仍然有效!
所以我认为您在声明和实现类层次结构时遗漏了一些重要的细节。

type
TShape = class(TObject)
  function IAm: string; virtual; abstract;
end;

TCircle = class(TShape)
  function IAm: string; override;
end;

TTriangle = class(TShape)
  function IAm: string; override;
end;


{ TCircle }

function TCircle.IAm: string;
begin
  Result := 'I am circle'
end;

{ TTriangle }

function TTriangle.IAm: string;
begin
  Result := 'I am triangle'
end;


procedure TForm1.Button6Click(Sender: TObject);
var
  Shape: TShape;
begin
  Shape := TCircle.Create;
  Memo1.Lines.Add(Shape.IAm);
  Shape.Free;
  Shape := TTriangle.Create;
  Memo1.Lines.Add(Shape.IAm);
  Shape.Free;
end;

output
  I am circle
  I am triangle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多