Inheritance/polymorphism concept

て烟熏妆下的殇ゞ 提交于 2020-01-07 09:24:03

问题


I have two binary files that contain a similar type of data so I want to create a unified viewer (TViewer) for both files. Some, methods are common for these two file types, some are not. So I created a base class TShape, and the from it TCircle and TTriangle.

Pseudo code:

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;

And I use it like this:

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;

When I do this it works:

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

but I want to do it directly like this:

Caption:= Viewer.Container.NoOfItems;

Obviously there is nothing wrong in using is except that I will have to use it in many many places (close to everywhere). There is a nicer way to achieve this unified viewer?

Update:

Actually, it may be also a performance problem. My file has a really big number of items (up to billions) so doing so many 'is/as' tests may actually have a real impact on speed.


回答1:


You're doing it wrong.

You need to change your code so that the container is not created until you know what type it needs to be, and then create the proper type:

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;

Here's a working example of using inheritance and polymorphism for you:

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.



回答2:


Real code and real output. Polymorphism still works!
So I think you have missed some important details while declaring and implementing your class hierarchy.

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


来源:https://stackoverflow.com/questions/23349117/inheritance-polymorphism-concept

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!