繁体   English   中英

Delphi:构造不调用重写的虚拟构造函数

Delphi: Construction not calling overridden virtual constructor

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

我有一个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;

除此之外从不调用我的构造函数,也不调用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;

TPicture中的版本:

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;

没有帮助。

更新二

很明显,我清楚地提供了清晰的截图,清楚地显示了我的清晰代码,清楚地表明我清楚的代码显然是清楚的。 很明显:

在此输入图像描述

更新三

这是一个使用OutputDebugString的非官方版本:

{ 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位)
  • 杰米:失败(Windows 7 64位)
  • 周杰伦:失败(Windows XP 32位)
  • 客户构建服务器:失败(Windows 7 32位)

这是源头。

2 个回复

这似乎是一个范围问题(以下是来自D5 Graphics.pas):

TGraphic = class(TPersistent)
...
protected
  constructor Create; virtual;
...
end;

TGraphicClass = class of TGraphic;

你没有任何问题覆盖Create ,并且当TGraphicClass(Value.ClassType).Create;时没有任何问题TGraphicClass(Value.ClassType).Create; 从Graphics.pas单元中调用。

但是,在另一个单元TGraphicClass(Value.ClassType).Create; 无法访问受保护的TGraphic成员。 所以你最终调用了TObject.Create; (这是非虚拟的)。

可能的解决方案

  • 编辑并重新编译Graphics.pas
  • 确保克隆方法子类在层次结构中较低。 (例如TBitmap.Create是公开的)

编辑:附加解决方案

这是获取对类的受保护成员的访问权的技术的变体。
不保证解决方案的稳健性,但似乎确实有效。 :)
我担心你必须进行自己的广泛测试。

type
  TGraphicCracker = class(TGraphic)
  end;

  TGraphicCrackerClass = class of TGraphicCracker;

procedure TForm1.Button1Click(Sender: TObject);
var
  a: TGraphic;
  b: TGraphic;
begin
  a := TMyBitmap.Create;
  b := TGraphicCrackerClass(a.ClassType).Create;
  b.Free;
  a.Free;
end;

值得一提的是:我下载了你的源代码(ZIP文件),并运行了CannotCloneGraphics.exe并得到了“无效”。 错误信息。 然后我在Delphi 2009中打开了项目(DPR文件),编译并运行它。 然后我没有得到任何错误消息,并且自定义构造器运行了四次,应该如此。

因此,这似乎是您的Delphi 5安装的问题。 确实,你的所有机器都有Delphi 5(升级时间?!)。 要么Delphi 5存在一些问题,要么所有机器都以同样的方式被“篡改”。

我很确定我有一个旧的Delphi 4 个人 某处。 我可能会安装它,看看那里发生了什么......

更新

我刚刚在虚拟Windows 95系统中安装了Delphi 4 Standard。 我试过这段代码:

  TMyBitmap = class(TBitmap)
  public
    constructor Create; override;
  end;

  ...

  constructor TMyBitmap.Create;
  begin
    inherited;
    ShowMessage('Constructor constructing!');
  end;

  ...

  procedure TForm1.Button1Click(Sender: TObject);
  var
    g, g2: TGraphic;
  begin
    g := TMyBitmap.Create;
    g2 := TGraphicClass(g.ClassType).Create;
    g.Free;
    g2.Free;
  end;

我只有一个消息框! 因此,这毕竟 Delphi 4(和5)的问题。 (对不起,大卫!)

2 Delphi虚拟构造函数

这个问题已经在这里有了答案: Delphi:了解构造函数 4个答案 我正在阅读这篇文章是因为我想了解class of [ClassName]的有用性,并且我已经看到它们声明了一个虚拟构造函数。 所以我做了一个测试,您可以在这里看到: 我从那篇文章中了解 ...

5 不调用构造函数

如何调用这个“内部”构造函数? 我以为它会自动初始化它? 我怎样才能简单地为属性“EngineStuff.PS”赋值? ...

6 通过id在旧式Delphi类上调用虚拟构造函数

在从流中读取对象内容之前,请先读取ID以确定对象类型。 为此,我必须存储流记录( TStreamRec )以将类类型链接到ID。 当我加载一个ID时,我必须搜索正确的流记录以在正确的类型上调用正确的构造函数。 不幸的是,我不得不使用旧式的Delphi类类型( TMyClass = ob ...

7 为什么此函数不调用move构造函数?

我正在关注Stephan T. Lavavej的视频讲座,也就是关于移动语义学的视频讲座: http ://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Standard-Template-Library-STL-/ C9-Step ...

2014-01-01 09:02:00 1 136   c++/ c++11
8 为什么不调用移动构造函数

所以我是新手移动语义,我正在测试以下代码。 我的理解是rvalue将调用移动构造函数,我期望A(“123”)将导致移动构造函数被调用。 但是当我运行它时,会调用复制构造函数。 ...

2018-08-24 18:50:04 2 118   c++
9 为什么不调用构造函数? [重复]

这个问题已经在这里有了答案: 最烦人的解析 1个答案 我对值初始化的尝试被解释为一个函数声明,为什么不使用a(());? 解决这个问题? 5个答案 最烦人的解析[重复] 2个答案 关于最令人烦恼的解析的一个令人困惑的细节 4个答案 ...

10 为什么不调用复制构造函数?

在第一种情况下,当MyClass(1, 2)调用用户定义的构造函数并返回一个对象时,我期望MyObj调用复制构造函数。 为什么它不需要为MyClass的第二个实例调用复制构造函数? ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2021 STACKOOM.COM