Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
180 views
Welcome To Ask or Share your Answers For Others

1 Answer

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.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...