Problem with named create function in delphi

I have a base class declared as

type TBaseClass=class protected constructor Create(LoadData:boolean;const Param1,Param2:string); overload; public Destructor Destroy; override; end; 

Now in another module, the child class TChid_Class , which descends from TBaseClass

  TChid_Class=class(TBaseClass) function Create(const Param1, Param2 : String;const Param3 : OleVariant ; var Param4 : LongInt): Integer;overload; constructor Create; overload; constructor Create(LoadData:boolean); overload; end; 

there is a function in this class called Create as constructors, the problem is that when I try to create an instance for TChid_Class , I have an access violation.

I wrote this little console application that shows the problem

 program TestClass; {$APPTYPE CONSOLE} uses Variants, SysUtils; type TBaseClass=class protected constructor Create(LoadData:boolean;const Param1,Param2:string); overload; public Destructor Destroy; override; end; TChid_Class=class(TBaseClass) function Create(const Param1, Param2 : String;const Param3 : OleVariant ; var Param4 : LongInt): Integer;overload; constructor Create; overload; constructor Create(LoadData:boolean); overload; end; { TBaseClass } constructor TBaseClass.Create(LoadData: boolean; const Param1, Param2: string); begin inherited Create; Writeln('constructor TBaseClass.Create(LoadData: boolean; const Param1, Param2: string);'); end; destructor TBaseClass.Destroy; begin //Code inherited; end; { TChid_Class } function TChid_Class.Create(const Param1, Param2: String; const Param3: OleVariant; var Param4: Integer): Integer; begin Writeln('function create'); Result:=0; end; constructor TChid_Class.Create; begin Writeln('constructor TChid_Class.Create'); Create(True); end; constructor TChid_Class.Create(LoadData: boolean); begin Writeln('constructor TChid_Class.Create(LoadData: boolean)'); //here is the access violation Create(LoadData,'Value 1','Value 2'); end; var Invoker : TChid_Class; Pid : integer; begin try Invoker:=TChid_Class.Create; try Invoker.Create('','',Unassigned,Pid) finally Invoker.Free; end; except on E:Exception do Writeln(E.Classname, ': ', E.Message); end; readln; end. 

If I rename the create function, the problem will disappear, but I am looking for a solution without renaming the create function or constructors.

using delphi 2007

Thanks in advance.

+4
source share
4 answers

With Delphi 7, I also get AV. Renaming a method or moving it (as suggested by Sertac Akyuz) captures AV.

What I discovered by looking at the assembler:

When creating a new object, an unnecessary value is placed in the dl register before calling the constructor.

 mov dl,$01 // dl set to 1 mov eax,[$00401268] call TChild_Class.Create 

Then, in the constructor on the begin string, ClassCreate is called when dl is non-zero.

 test dl,dl jz +$08 //if dl = 0 then do not call ClassCreate add esp,-$10 call -$00000396 //calls ClassCreate 

But then, with your code, the compiler sets dl to 1 again, and then calls Create(True) , so in the begin string TChid_Class.Create(LoadData: boolean); ClassCreate is called again, which results in AV.

After renaming your function or moving its declaration, the compiler will clear dl ( xor edx,edx ) instead of setting it to 1, before calling Create(True) .

I assume this is a bug in the Delphi compiler, which is fixed in Delphi 2010 and above.

+3
source

Partial answer: in your TChid_Class.Create constructor (LoadData: boolean) you are missing the 'inherited' in your Create call. This captures AV in the sample code if you call * TChid_Class.Create (True) * in your demo project.

 constructor TChid_Class.Create(LoadData: boolean); begin Writeln('constructor TChid_Class.Create(LoadData: boolean)'); //here is the access violation inherited Create(LoadData,'Value 1','Value 2'); //add "INHERITED" end; 
+2
source

You are using the wrong way to create an object! You cannot call more than one constructor in a class one at creation time, but you can only inherit creation . So the correct way is something like:

 constructor TChid_Class.Create(LoadData: boolean = True); begin Writeln('constructor TChid_Class.Create(LoadData: boolean)'); //here is the access violation inherited Create(LoadData,'Value 1','Value 2'); end; 

The reserved word inherited tells the parent constructor that this object was created in the constructor of the child class. Tested under D2007!

+1
source

This was a compiler error until the latest Delphi 2007 updates.
It works from Delphi 2009 and above.

Renaming the Create function to Initialize solves your problem. This is not only a workaround, but also correct for fixing the error, and from the point of view of coding:
As a rule, there should be a clear difference in the construction and initialization of object instances.

  • Construction should be short and not make exceptions.
  • Initialization may take longer and may throw an exception.

- Jeroen

0
source

Source: https://habr.com/ru/post/1332163/


All Articles