我有这些课程和程序:
TParent = class(TObject);
TChild1 = class(TParent);
TChild2 = class(TParent);
Procedure DoSomething(obj:TParent);
我想要做的是obj
是TParent
而不是后代引发异常。
我想过做这样的事情:
if obj.classname = TParent.classname then raise exception.create....
但似乎有点 hackish(TM)
更多:我的意图是能够传递共享属性/过程的对象。经过深思熟虑后,根本不需要TParent Object,我需要的是我的答案中显示的接口对象。
答案 0 :(得分:34)
您可能会发现以下TObject
类方法很有用:
那么,您可以使用类似下面的代码(未经测试,此时没有Delphi)来实现您想要的(从TParent而不是TDescendant下载?):
if obj.ClassType.InheritsFrom(TParent)
and not obj.ClassType.InheritsFrom(TDescendant) then...
或者,如果我误解了你只是想看一个对象是否是一个TParent,而不是任何一种后代,请尝试:
if obj.ClassType = TParent then...
通过metaclasses提供对类的访问,Delphi远远超过了它的时间,因此,不仅仅是检查类名,您还可以访问实际的类对象。
答案 1 :(得分:11)
你走在正确的轨道上,但不是比较类名,而是检查ClassType
属性会更简单。
if obj.ClassType = TParent then raise exception.create....
答案 2 :(得分:11)
面向对象编程的良好实践表明不应该这样做。你所描述的是对Liskov substitution principle的直接违反,其中声明:
程序中的对象应该是 可以替换他们的实例 没有改变的亚型 该计划的正确性
我认为你应该解释一下你试图解决的问题,然后一个更好的方法可能会变得明显。
答案 3 :(得分:3)
另一种方法:在TParent中引入一个抽象方法,比如 CheckValidChild ,并在后代类中覆盖它。现在当你调用 obj.CheckValidChild 时,如果obj的实例属于TParent类,你会得到一个 EAbstractError 。
答案 4 :(得分:0)
我想我已经解决了我想要做的事情,它昨晚让我头疼。
iParentInterface = interface(IUnknown);
TChild1 = class(TInterfacedObject,iParentInterface);
TChild2 = class(TInterfacedObject,iParentInterface);
Procedure DoSomething(obj:iParentInterface);
答案 5 :(得分:0)
有一个保留字(IS)来检查一个实例是一个类型还是一个类型的子项。
示例:
TFruit = class
end;
TApple = class(TFruit)
end;
TOrange = class(TFruit)
end;
procedure check;
var
a: TApple;
b: TOrange;
begin
if (a is TFruit) then showmessage('a is a fruit');
if (b is TFruit) then showmessage('b is also a fruit');
end;