InheritsFrom和is运算符之间有什么区别?

时间:2017-02-10 08:00:52

标签: delphi

在所有情况下我都记得,以下说明给出了相同的结果:

type
  TMyClass = class(TObject);
  TMyChildClass = class(TMyClass);

var
  MyObj : TMyChildClass;

procedure TForm1.Test();
var
  ResultA : Boolean;
  ResultB : Boolean;
begin
  //Using TObject.InheritsFrom
  ResultA := MyObj.InheritsFrom(TMyClass);

  //Using 'is' operator
  ResultB := MyObj is TMyClass;

  //Showing results
  ShowMessage(
    'InheritsFrom = ' + BoolToStr(ResultA, True) + sLineBreak +
    'is = ' + BoolToStr(ResultB, True)
  );
end;

使用is运算符代替TObject.InheritsFrom函数有什么不同吗?

3 个答案:

答案 0 :(得分:9)

是的,有区别。 InheritsFrom是类函数,它的主要目的是测试类IS(从某个类继承)。

您不能在课程上使用is运算符。

TMyChildClass is TMyClass无法编译,但您可以使用TMyChildClass.InheritsFrom(TMyClass)代替。

答案 1 :(得分:6)

is运算符构建于InheritsFrom之上。所以,

obj is TSomeClass

实现为

(obj <> nil) and obj.InheritsFrom(TSomeClass)

表达式obj.InheritsFrom(TSomeClass)可能有点令人困惑,因为看起来InheritsFrom是一个实例方法。实际上InheritsFrom是一个类方法,obj的运行时类作为InheritsFrom指针传递给Self

基本上isInheritsFrom执行相同的任务,至少在限制注意类时。请注意,is更通用,也可以与接口一起使用,例如。

有明显的语法差异。即is需要一个实例,而InheritsFrom是一个类函数。虽然,正如我们所看到的,Delphi语言确实支持在实例引用上调用类函数。另一个明显的区别是is有一个nil引用的内置测试。

这些只是语法上的差异,但基本操作是相同的,is调用InheritsFrom这一事实证明了这一点。

答案 2 :(得分:1)

我想提到至少一种情况

obj is TSomeClass

运算符的行为不完全与

(obj <> nil) and obj.InheritsFrom(TSomeClass)

当编译器“认为” obj只能是TSomeClass成员时,它将跳过TObject.InheritsFrom()调用(使用 is 运算符时),并且仅测试nil指针。可以通过以下测试代码(在10.2.3 Tokyo和10.3.3 Rio中进行测试)确认这一点:

procedure TestForTStringList(obj: TStringList);
begin
  if obj.InheritsFrom(TStringList) then
  begin
    //
  end;

  if obj is TStringList then
  begin
    //
  end;
end;

此代码产生以下汇编代码

enter image description here

在此方法中,我们可以看到obj.InheritsFrom()实际上调用了TObject.InheritsFrom()方法。另一方面,与 is 运算符相关的代码仅检查nil指针。

在无法在编译时确定类的情况下,与编译器为 is 运算符生成的代码进行比较:

enter image description here

上面,该变量被声明为TObject,因此编译器实际上调用了System.IsClass(),即:

function _IsClass(const Child: TObject; Parent: TClass): Boolean;
begin
  Result := (Child <> nil) and Child.InheritsFrom(Parent);
end;

您可能会认为这没有什么区别,但是在某些特定的调试方案中却没有关系:使用FastMM时,将选中检查释放对象上的方法调用的选项。在这种情况下,FastMM用TFreedObject实例替换实际对象。

在这种情况下,obj实际上是一个TFreedObject实例(而不是TStringList)。

obj.InheritsFrom(TStringList) = False

另一方面

(obj is TStringList) = True

因为该代码实际上只会检查nil指针。

PS:无论编译器优化设置如何,生成的代码都是相同的