我有两个包含相似类型数据的二进制文件,因此我想为这两个文件创建一个统一的查看器(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
没有任何问题,只是我必须在很多地方(靠近所有地方)使用它。有一个更好的方法来实现这个统一的查看器?
实际上,它也可能是性能问题。我的文件有很多项目(高达数十亿)所以做了这么多'是/因为'测试可能实际上对速度有实际影响。
答案 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