Delphi 遗传/多态概念
我有两个二进制文件,其中包含类似类型的数据,因此我想为这两个文件创建一个统一的查看器TViewer。 对于这两种文件类型,有些方法是通用的,有些则不是。所以我创建了一个基类 t形状,以及从中导出的t圆形和t三角形 伪代码:Delphi 遗传/多态概念,delphi,oop,Delphi,Oop,我有两个二进制文件,其中包含类似类型的数据,因此我想为这两个文件创建一个统一的查看器TViewer。 对于这两种文件类型,有些方法是通用的,有些则不是。所以我创建了一个基类 t形状,以及从中导出的t圆形和t三角形 伪代码: TShape = class(TObject) function NoOfItems: integer; virtual; abstract; end; TCircle = class(TShape) function NoOfItems: integer; ov
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;
Caption:= Viewer.Container.NoOfItems;
显然,使用is并没有什么错,只是我将不得不在任何地方附近的许多地方使用它。有更好的方法来实现这个统一的查看器吗
更新:
实际上,这可能也是一个性能问题。我的文件中有大量的项,多达数十亿项,因此执行如此多的“是/是”测试实际上可能会对速度产生真正的影响。真正的代码和真正的输出。多态性仍然有效! 因此,我认为您在声明和实现类层次结构时遗漏了一些重要的细节
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
你做错了
您需要更改代码,以便在知道容器需要的类型之前不会创建容器,然后创建适当的类型:
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;
当然,您可以使用IntVar:=Viewer.Container.NoOfItems;-这是典型的多态性用法,您根本不必对其进行类型转换,也不必对示例中的代码进行类型转换,这意味着这很可能不是您真正的代码。实际上,这不可能是您真正的代码,因为您已将NoOfItems声明为返回整数的函数,但您直接将其分配给标题。如果需要帮助,请发布真实代码。@MBo-它将调用TShape的方法。什么都不做是抽象的。@KenWhite-是的。这不是真正的代码。真正的代码是大到可以张贴在这里。我将尝试制作一个小的可编译演示。无论如何,Viewer.Container.NoOfItems调用TShape的方法,该方法不返回任何内容!好啊我在表格中加了摘要。现在很明显,Viewer.Container.NoOfItems失败了。在您知道它需要什么类型之前,容器不会被创建。。。正当明显地我不知道我是怎么搞砸的。非常感谢+1并接受。我将考虑使用工厂模式来决定创建什么。如果FillType=圆形,则。。。有点臭。@Andy_D:问题不在于使用什么设计模式。这就是为什么继承和多态性不能在这里工作?这就是我的答案。不过,感谢您的意见:-我知道@KenWhite,我只是观察到工厂模式将使解决方案更加灵活和可读
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.