继承的类函数会导致“不兼容的类型”和“不兼容的类型”。

时间:2014-04-03 12:26:19

标签: delphi inheritance delphi-xe5

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

描述图元素的单位:

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);

但是因为它是一个相当大的软件项目,比上面的代码复杂得多,我想知道它是否真的是更好的解决方案,而不仅仅是类型转换每次使用该功能时。

非常感谢任何关于如何以一种很好的方式解决这个问题的想法。

3 个答案:

答案 0 :(得分:1)

包含的最后一个单元'拥有'碰撞时的类型名称。由于这是包含子类的单元ElementsDiff,因此主代码使用这些类。

问题是,ReturnSomething返回基类Elements.TElementA的实例。

要解决这个问题,您可以(在其他方面)在Main中声明您的变量,如下所示:

var
  FElementA: Elements.TElementA;
  FElementB: Elements.TElementB;

这样,只要您不使用仅存在于后代中的任何方法或属性,变量就可以包含基类或后代类。

但也许最好给差异类别​​命名以避免混淆。这些类不必具有相同的名称。这也有效:

// In ElementDiff:
TElementBDiff = class(TElementB)

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

答案 1 :(得分:0)

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

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

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

答案 2 :(得分:0)

我认为你正在寻找这样的东西:

TElementB = class(Elements.TElementB)
  procedure DrawSomething; override;
  function ReturnSomething: tElementA; reintroduce;
end;

请注意,当您实现新的ReturnSomething时,您总是返回一个ElementsDiff.tElementA类型的对象。

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

FElementA := FElementB.ReturnSomething as tElementA;

这将确保对象真正属于您期望的类型。