我有两个类:一个基类和一个派生类基类定义了一个带有参数的虚拟方法:
function ToName(MsgIfNil:string=''); virtual;
派生类重新定义方法:
function ToName(MsgIfNil:string=''); reintroduce;
两种方法的实现都类似于这段代码:
function TBaseClass.ToName(MsgIfNil:string)
begin
if (Self=nil) then
Result := MsgIfNil
else
Result := Self.SomeProperty;
end;
问题是:
1)如果我不在派生类中重新引入该方法,而是使用常规覆盖关键字,则对该方法的任何调用都会触发访问冲突
2) 当我从一个为 nil 的对象调用该方法,并且该对象的假定类是 TBaseObject 时,它崩溃 (AV) 而不是调用基本虚拟方法
如果方法中没有定义参数,则调用正确的方法,没有任何 AV。即使派生类中的方法被覆盖,它也能正常工作。
请注意,上述解决方案适用于从 TBaseClass 派生的任何类的对象
如何定义一个可以用 Self=nil 调用的虚拟方法,可以是虚拟的并且可以使用参数?
我当然必须增强我对内部虚拟方法调用管道的理解......
注意:在我的用例中,调用 nil 对象是合法的。它不用于隐藏异常,而是用于报告非链接对象。示例:myEdit.Text := APerson.Manager.ToName('未定义经理');
感谢您提供有关适当解决方案的任何建议
使用带有 upd5 的 Delphi 2010
编辑:添加更完整的触发 AV 的代码示例
TBaseClass = class(TObject)
private
FMyName: string;
public
property MyName: string read FMyName;
function ToName(MsgIfNil:string=''):string; virtual;
end;
TDerivedClass = class(TBaseClass)
private
FSpecialName: string;
public
property SpecialName:string read FSpecialName;
function ToName(MsgIfNil:string=''):string; reintroduce;
end;
TBaseClass.ToName(MsgIfNil:string):string;
begin
if (Self=nil) then
Result := MsgIfNil
else
Result := MyName;
end;
TDerivedClass.ToName(MsgIfNil:string):string;
begin
if (Self=nil) then
Result := MsgIfNil
else
Result := SpecialName;
end;
// Now a sample program
var
aPerson: TBaseClass;
aSpecialist: TDerivedClass;
begin
aPerson := TBaseClass.Create;
aPerson.MyName := 'a person';
aSpecialist := TDerivedClass.Create;
aSpecialist.SpecialName := 'a specialist';
aSpecialist := nil; // For example sake, never do this in my use case :)
// This works here,
// but triggers an AV if ToName is marked as override instead of reintroduce
ShowMessage('Name of the specialist: '+aSpecialist.ToName('No specialist!'));
aPerson := nil;
// This triggers an AV, TBaseClass.ToName is never called
ShowMessage('Name of the person: '+aPerson.ToName('No person!'));
end;
上面的代码可能无法编译,这只是一个更完整的例子
外卖
我现在明白 VMT 链接到对象引用,并且无论对象类如何,都无法在 nil 对象上调用虚拟方法(该对象甚至不会查看其声明的类型以获取 ToName 方法的匹配地址)
我接受了 hvd 的解决方案,因为它对于必须检查 vs nil 的方法非常有效(只需添加一种基本方法)。
谢谢大家的回答,