我编写了一个自定义SDL GUI工具包(源代码在http://sourceforge.net/projects/lkgui/files/上),我遇到了继承对象的问题。
当对象在主程序中时,不调用构造函数,因此程序没有正确初始化对象,并且在某些命令后崩溃(具体来说,TStartGameButton继承自GUI_Canvas继承自GUI_Element和任何未定义的内容)在GUI_Element中使用EAccessViolation使程序崩溃。当对象放在一个单元内时,这个问题就消失了。
我知道我可以把它放在单元中,但它会导致一些丑陋的代码,希望可以避免。
有谁知道为什么会发生这种情况以及如何避免这种情况?
答案 0 :(得分:3)
自Delphi 2发布以来,旧式的Delphi对象已经被打破,也许更早。当它们具有编译器管理类型的字段(例如string
或动态数组)时,它们不能很好地继承。 2004年 comp.lang.pascal.delphi.misc 上有a discussion about it。以下是重现它的代码:
type
TBase = object
public
s: string;
end;
TDerived = object(TBase)
end;
procedure test;
var
obj: TDerived; //okay for TBase!
begin
assert(obj.s = '', 'uninitialized dynamic variable');
end;
事实上,TBase
只是偶然的,因为函数的序言代码恰好是如何生成的。在该函数中添加其他代码可能会使其崩溃。
实际上,它与您所观察到的完全一样 - 旧式对象无法正确初始化。他们的字符串字段不会以空字符串开头;相反,他们持有垃圾,因此甚至不可能在不使用FillChar
之类的情况下自己初始化它们。
这似乎是由于变量是本地变量。单位范围(“全局”)变量似乎正常。在单位范围内声明但仅由单元的初始化部分使用的变量,或仅在程序范围内使用且仅在DPR文件的主开始 - 结束块中使用的变量,由编译器视为局部变量,因此它们不会设置为全部-bits-zero就像他们的全球同行一样。将变量声明移动到单元但继续在DPR文件中使用它时,它会升级到“全局”状态。
您的TGUI_Element
类型的string
成员名为DbgName
,看起来这是您在类型层次结构中唯一的字符串字段。拿出来,或者改为ShortString
,我敢打赌你的崩溃会消失,至少是暂时的。
答案 1 :(得分:0)
为什么要为所有对象提供单独的命名构造函数而不是将它们设置为虚拟?
type tx = object
constructor init; virtual;
end;
txx = object(tx)
constructor init; virtual; // like override in Delphi classes.
end;
如果您需要一个可视化的层次结构来查看,请查看Free Vision,它几乎演示了TP对象模型的每个方面
糟糕 TP模型中无法使用虚拟构造函数