【发布时间】:2011-07-16 21:59:29
【问题描述】:
我有一个 TBitmap 的后代示例:
TMyBitmap = class(TBitmap)
public
constructor Create; override;
end;
constructor TMyBitmap.Create;
begin
inherited;
Beep;
end;
在运行时,我构造其中一个TMyBitmap 对象,将图像加载到其中,并将其放入表单上的TImage:
procedure TForm1.Button1Click(Sender: TObject);
var
g1: TGraphic;
begin
g1 := TMyBitmap.Create;
g1.LoadFromFile('C:\...\example.bmp');
Image1.Picture.Graphic := g1;
end;
在TPicture.SetGraphic 内部,您可以看到它通过构造一个新图形并在新构造的克隆上调用.Assign 来复制图形:
procedure TPicture.SetGraphic(Value: TGraphic);
var
NewGraphic: TGraphic;
begin
...
NewGraphic := TGraphicClass(Value.ClassType).Create;
NewGraphic.Assign(Value);
...
end;
构造新图形类的行:
NewGraphic := TGraphicClass(Value.ClassType).Create;
正确调用我的构造函数,一切正常。
我想做类似的事情,我想克隆一个TGraphic:
procedure TForm1.Button1Click(Sender: TObject);
var
g1: TGraphic;
g2: TGraphic;
begin
g1 := TMyBitmap.Create;
g1.LoadFromFile('C:\...\example.bmp');
//Image1.Picture.Graphic := g1;
g2 := TGraphicClass(g1.ClassType).Create;
end;
除了 this 从不调用我的构造函数,也不会调用 TBitmap 构造函数。它只调用TObject 构造函数。施工后:
g2.ClassName: 'TMyBitmap'
g2.ClassType: TMyBitmap
类型是正确的,但它没有调用我的构造函数,但其他地方的代码相同。
为什么?
即使在这个假设的人为示例中,它仍然是一个问题,因为TBitmap 的构造函数没有被调用;内部状态变量未初始化为有效值:
constructor TBitmap.Create;
begin
inherited Create;
FTransparentColor := clDefault;
FImage := TBitmapImage.Create;
FImage.Reference;
if DDBsOnly then HandleType := bmDDB;
end;
TPPicture中的版本:
NewGraphic := TGraphicClass(Value.ClassType).Create;
反编译为:
mov eax,[ebp-$08]
call TObject.ClassType
mov dl,$01
call dword ptr [eax+$0c]
mov [ebp-$0c],eax
我的版本:
g2 := TGraphicClass(g1.ClassType).Create;
反编译为:
mov eax,ebx
call TObject.ClassType
mov dl,$01
call TObject.Create
mov ebx,eax
更新一
将“克隆”推送到单独的函数:
function CloneGraphic(Value: TGraphic): TGraphic;
var
NewGraphic: TGraphic;
begin
NewGraphic := TGraphicClass(Value.ClassType).Create;
Result := NewGraphic;
end;
没用。
更新二
显然,我清楚地提供了清晰的屏幕截图,清楚地显示了我的清晰代码,清楚地表明我的清晰代码显然是所有清晰的。很明显:
更新三
这是带有OutputDebugStrings 的明确版本:
{ TMyGraphic }
constructor TMyBitmap.Create;
begin
inherited Create;
OutputDebugStringA('Inside TMyBitmap.Create');
end;
function CloneGraphic(Value: TGraphic): TGraphic;
var
NewGraphic: TGraphic;
begin
NewGraphic := TGraphicClass(Value.ClassType).Create;
Result := NewGraphic;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
g1: TGraphic;
g2: TGraphic;
begin
OutputDebugString('Creating g1');
g1 := TMyBitmap.Create;
g1.LoadFromFile('C:\Archive\-=Images=-\ChessvDanCheckmateIn38.bmp');
OutputDebugString(PChar('g1.ClassName: '+g1.ClassName));
OutputDebugStringA('Assigning g1 to Image.Picture.Graphic');
Image1.Picture.Graphic := g1;
OutputDebugString('Creating g2');
g2 := Graphics.TGraphicClass(g1.ClassType).Create;
OutputDebugString(PChar('g2.ClassName: '+g2.ClassName));
OutputDebugString(PChar('Cloning g1 into g2'));
g2 := CloneGraphic(g1);
OutputDebugString(PChar('g2.ClassName: '+g2.ClassName));
end;
原始结果:
ODS: Creating g1 Process Project2.exe ($1138)
ODS: Inside TMyBitmap.Create Process Project2.exe ($1138)
ODS: g1.ClassName: TMyBitmap Process Project2.exe ($1138)
ODS: Assigning g1 to Image.Picture.Graphic Process Project2.exe ($1138)
ODS: Inside TMyBitmap.Create Process Project2.exe ($1138)
ODS: Creating g2 Process Project2.exe ($1138)
ODS: g2.ClassName: TMyBitmap Process Project2.exe ($1138)
ODS: Cloning g1 into g2 Process Project2.exe ($1138)
ODS: g2.ClassName: TMyBitmap Process Project2.exe ($1138)
ODS: g1.ClassName: TMyBitmap Process Project2.exe ($1138)
以及格式化结果:
Creating g1
Inside TMyBitmap.Create
g1.ClassName: TMyBitmap
Assigning g1 to Image.Picture.Graphic
Inside TMyBitmap.Create
Creating g2
g2.ClassName: TMyBitmap
Cloning g1 into g2
g2.ClassName: TMyBitmap
g1.ClassName: TMyBitmap
更新四
我尝试关闭所有编译器选项:
注意:不要关闭Extended syntax。没有它,您将无法分配函数的Result(未声明的标识符结果)。
更新五
按照@David 的建议,我尝试在其他一些机器上编译代码(都是 Delphi 5):
- Ian Boyd(我):失败(Windows 7 64 位)
- 戴尔:失败(Windows 7 64 位)
- 戴夫:失败(Windows 7 64 位)
- 克里斯:失败(Windows 7 64 位)
- Jamie:失败(Windows 7 64 位)
- Jay:失败(Windows XP 32 位)
- 客户构建服务器:失败(Windows 7 32 位)
【问题讨论】:
-
也许你应该篡改编译器指令,一些优化可能会影响代码的虚拟方法表调用,并且不会影响预编译的 VCL 库。
-
@too,例如,哪个编译器指令影响虚拟方法表调用正确发生?
-
@Ian 你确定 g1.classtype 在你的 Button1Click 例程的最后一行之前仍然是 TMyBitmap 吗?我敢打赌,班级在未显示的行中发生了变化。作为@David,我在Delphi XE中也收到了两声哔哔声,我手头没有D5可供测试,但当时我似乎不太可能出现这样的错误(甚至在D1中也没有)。 :)
-
@jachguate 我用 Delphi 2010 和 Delphi 6 进行了测试。显然@Ian 有一些我们看不到的额外代码。
-
@David Heffernan。我已经用我的代码截图更新了问题
标签: delphi constructor virtual delphi-5