继承/多态概念

时间:2014-04-28 18:58:47

标签: delphi oop

我有两个包含相似类型数据的二进制文件,因此我想为这两个文件创建一个统一的查看器(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没有任何问题,只是我必须在很多地方(靠近所有地方)使用它。有一个更好的方法来实现这个统一的查看器?

更新

实际上,它也可能是性能问题。我的文件有很多项目(高达数十亿)所以做了这么多'是/因为'测试可能实际上对速度有实际影响。

2 个答案:

答案 0 :(得分:4)

你做错了。

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

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 :(得分: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