delphi中父类和子类之间的转换

Posted

技术标签:

【中文标题】delphi中父类和子类之间的转换【英文标题】:Casting between parent and child classes in delphi 【发布时间】:2009-03-25 13:15:18 【问题描述】:

我正在编写一些针对两个版本非常相似的硬件的软件,在我使用 API 初始化硬件之前,我无法知道我会返回哪种类型的硬件。

因为硬件非常相似,我计划有一个父类(TParent),它有一些抽象方法(用于硬件不同的地方),然后是两个子类(TChildA,TChildB),它们以硬件相关的方式实现这些方法.

所以我会先实例化一个 TParent 的对象,检查它是什么类型,然后将其转换为正确的子对象。

但是,当我这样做并调用在子类中完全实现的抽象方法之一时,我得到一个 EAbstractError。

例如:

myHardware:=TParent.Create();

if myHardware.TypeA then
   myHardware:=TChildA(myHardware)
else
   myHardware:=TChildB(myHardware);

myHardware.SomeMehtod();

我假设我不能将父类转换为子类,并且可能有更好的方法来做到这一点。有什么指点吗?

【问题讨论】:

为什么要强制转换为子类?多态性的重点是避免这种情况。 @OregonGhost:恕我直言,一个非常无益的评论。很好,提问者知道这是错误的,但不知道足够的 OO 来知道为什么它是错误的。他们在寻求你的帮助,而不是嘲笑。曾经有一段时间你也不知道 OO 我不认为 OregonGhost 的评论具有讽刺意味。恕我直言,他问了一个重要问题。 向 OregonGhost 道歉所以,现在我再次阅读它,我发现确实反应过度,当我写该评论时我一定有一个错误:) RobS:今天很累,所以乱说,很高兴我能帮上忙,也感谢 mghie。 【参考方案1】:

您需要一个工厂方法来根据您使用的硬件类型返回正确的类...

function CreateHardware(isTypeA: Boolean): TParent;
begin
  if IsTypeA then Result := TChildA.Create
  else Result := TChildB.Create;
end;
...

var
  myHardware: TParent;
begin
  myHardware := CreateHardware(True);
  myHardwarde.SomeMethod;
end;

...或者您可以使用State pattern。

这两种方法的共同点是您的 TParent 类不具备确定硬件类型的知识。该知识被转移到工厂方法、工厂方法的调用者、工厂本身或状态类中。

【讨论】:

+1。您的答案对提问者来说更好,并且比我的情况更普遍。不错的一个 +1。初始化硬件以确定其类型是我想尽可能少做的事情(它的机械压力很大),但我仍然想在类中封装初始化,而这样我需要先初始化硬件,如果我理解的话正确吗? @RobS - 在某些时候,您“必须”知道应该创建哪个 Child。如果初始化实际硬件是确定类型的要求,那么除了初始化它之外,我看不到任何其他方法(除了使用模拟对象)。初始化应该只进行一次。 ... 硬件的初始化可以推迟到你真正调用工厂方法。 这似乎是错误的解决方案,因为要创建的特定类的信息在至少执行了一些初始化之前是不可用的。 pImpl 成语看起来更合适。【参考方案2】:

感谢 Binary Worrier 和 Mghie 在这种情况下为我指明了正确的方向。在最小化硬件初始化不是问题的情况下,Lieven 给出的答案将是更简单的方法。

pImpl 成语讨论elsewhere on SO

这是我如何理解伪德尔福代码中的实现(请注意,我没有为此烦恼公共/私人区别):

class TParent 
  procedure SomeMethod(); abstract;
end;

class TChildA (TParent)
  procedure SomeMethod(); override;
end;

class TChildB (TParent)
  procedure SomeMethod(); override;
end;

class THardware
 HardwareSpecficMethods: TParent;
 procedure SomeMethod;
 constructor Create();

contrsuctor THardware.Create();
begin
 InitializeHardware();
 If Hardware.TypeA then
  HardwareSpecificMethods:=TChildA.Create()
 else
  HardwareSpecificMethods:=TChildB.Create();
end;

procedure THardware.SomeMethod();
begin
  HardwareSpecificMethods.SomeMethod();
end;
end; class THardware

【讨论】:

@RobS - 您刚刚使用了您的第一个状态模式实现。恭喜:)【参考方案3】:

你是对的,你不能也不应该从基类转换为派生类。

我假设您不想让 Child 对象重新运行 Parent 构造函数?

如果是这样。 . .

删除现有的父/子关系,您将只有一个硬件类。 对于特定的 ChildA 和 ChildB 功能,创建一个新的继承模式,这样您就有一个 ISpecificHardwareTasks 接口或基类,以及两个派生类(SpecificA 和 SpecificB)。

当硬件构建它自己时,它知道它正在使用什么类型的硬件,然后它会创建一个 SpecificA 或 SpecificB 的实例。这个实例是硬件私有的。

硬件公开了包装 ISpecificHardWareTasks 方法的方法(如果有意义,它甚至可以实现该接口)。

如果有必要,特定类可以引用 Hardware 类(虽然我不知道您是否可以访问构造函数中的 this 指针,但我的 Delphi 已经生锈了)

希望这些闲聊有所帮助。

【讨论】:

+1。你的第二句话一针见血。当我正确理解您的“胡言乱语”(您的话不是我的;))时,我很可能会执行您的建议。 +1 表示答案,尽管它可能不太清楚。重要的一点是继承在这里是错误的工具。 OP 应该实现一个通用的硬件类,并使用 pImpl 习惯用法作为细节。 @mghie。感谢您指出它的名称,如果可以的话,我会为您的评论 +1。

以上是关于delphi中父类和子类之间的转换的主要内容,如果未能解决你的问题,请参考以下文章

Java 如何实现父类转换为子类的效果?

子类和父类的转换!谢谢!

Java 父类子类转换的问题

SV中父类与子类句柄转换,即子类的扩展类与父类句柄转换等问题

SV中父类与子类句柄转换,即子类的扩展类与父类句柄转换等问题

SV中父类与子类句柄转换,即子类的扩展类与父类句柄转换等问题