Delphi 继承的类函数导致';不兼容类型';

Delphi 继承的类函数导致';不兼容类型';,delphi,inheritance,delphi-xe5,Delphi,Inheritance,Delphi Xe5,我们有一个运行良好的软件项目(DelphiXe5)。它基本上显示了一个包含各种元素的图表。现在为了扩展它,我们必须重新实现绘图方法,这也很好。但是,对于继承类中的其他函数,我们会遇到不兼容的类型问题 描述图表元素的单元: unit Elements; type TElementA = class procedure DrawSomething; virtual; end; TElementB = class FElementA: TElementA; procedure Draw

我们有一个运行良好的软件项目(DelphiXe5)。它基本上显示了一个包含各种元素的图表。现在为了扩展它,我们必须重新实现绘图方法,这也很好。但是,对于继承类中的其他函数,我们会遇到不兼容的类型问题

描述图表元素的单元:

unit Elements;

type
TElementA = class
  procedure DrawSomething; virtual;
end;

TElementB = class
  FElementA: TElementA;
  procedure DrawSomething; virtual;
  function ReturnSomething: TElementA;
end;
第二个单元使用第一个单元,基本上重新执行绘图程序:

unit ElementsDiff;

uses Elements;

type
TElementA = class(Elements.TElementA)
  procedure DrawSomething; override;
end;

TElementB = class(Elements.TElementB)
  procedure DrawSomething; override;
end;
使用这些类的过程如下所示:

unit Main;

uses
  Elements,
  ElementsDiff;

implementation

procedure MainProcedure;
var
  FElementA: TElementA;
  FElementB: TElementB;
begin
  FElementA := TElementA.Create;
  FElementB := TElementB.Create;
  // do some stuff...
  // ................

  FElementA := FElementB.ReturnSomething;
end;
编译时,它当然不会编译最后一行的原因。我们得到了一个很好的错误:

Incompatible types: 'ElementsDiff.TElementA' and 'Elements.TElementA'
含义:ReturnSomething返回“Elements.TElementA”类型,但FElementA是“ElementsDiff.TElementA”类型。 我理解问题的原因(这里已经回答了很多次),最简单的解决方法就是进行类型转换,即

FElementA := TElementA(FElementB.ReturnSomething);
但由于这是一个相当大的软件项目,比上面的代码复杂得多,我想知道是否有比每次使用该函数时只进行类型转换更好的解决方案


非常感谢您对如何以良好方式解决此问题的任何想法。

解决这些名称冲突的最简单方法是在unit Main中提供一个本地别名:

type
  TElementA = Elements.TElementA;
  TElementB = Elements.TElementB;

这样,编译器就知道您要使用哪个TElementA。

我想您正在寻找类似这样的东西:

TElementB = class(Elements.TElementB)
  procedure DrawSomething; override;
  function ReturnSomething: tElementA; reintroduce;
end;
var
  FElementA: Elements.TElementA;
  FElementB: Elements.TElementB;
只是要小心,当您实现新的ReturnSomething时,您总是返回ElementsDiff.tElementA类型的对象

我建议使用AS而不是显式的类型转换

FElementA := FElementB.ReturnSomething as tElementA;

这将确保对象确实是您期望的类型

插入的最后一个单元在发生冲突时“拥有”类型名称。因为这是包含子类的单元
ElementsDiff
,所以主代码使用这些类

那么,问题是ReturnSomething返回一个实例,即基类
Elements.TElementA

要解决此问题,您可以(除其他外)在Main中声明变量,如下所示:

TElementB = class(Elements.TElementB)
  procedure DrawSomething; override;
  function ReturnSomething: tElementA; reintroduce;
end;
var
  FElementA: Elements.TElementA;
  FElementB: Elements.TElementB;
这样,只要不使用任何只存在于子体中的方法或属性,变量就可以包含基类或子体类而不会出现问题

但也许最好给diff类起一个不同的名称,以避免混淆。这些类不必具有相同的名称。这也会起作用:

// In ElementDiff:
TElementBDiff = class(TElementB)

// In Main:
var
  ElementB: TElementB;
begin
  ElementB := TElementBDiff.Create;

这可能解决不了问题。FElementA故意属于ElementsDiff.TElementA类型是完全正确的。这个问题不是一个典型的名称冲突问题。@Uwe,我认为这个问题正是一个典型的名称冲突问题。代码使用标记
TElementA
,期望引用元素单元中定义的类型,但最终得到的是元素diff中定义的类型。该函数从元素返回类型,因此编译器正确地拒绝尝试将一个类型分配给另一个类型的代码。如果调用者知道运行时类型比声明的类型更具体,那么调用者可以稍后进行类型转换。您的意图是主要声明的fElementB类型为ElementsDiff.tElementB吗?我假设您说的“function ReturnSomething:FElementA;”是指“function ReturnSomething:tElementA;”@用户1008646:当然可以。。小错误,我改正了。谢谢