开发者

problem with function named create in delphi

开发者 https://www.devze.com 2023-01-30 09:41 出处:网络
i have a base class declarated like this type TBaseClass=class protected constructor Create(LoadData:boolean;const Param1,Param2:string); overload;

i have a base class declarated like this

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

Now in another unit a child class TChid_Class which descend 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;

in this class exist a function called Create like the constructors, the problem is , when i try to create a instance to the TChid_Class i have an access violation.

i wrote this small console app which show 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 : St开发者_如何学Cring;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 function create, the problem is go away, but i am looking for a solution without rename the create function or the constructors.

using delphi 2007

Thanks in advance.


With Delphi 7 I get an AV too. Renaming the method or moving it (as suggested by Sertac Akyuz) fixes the AV.

What I discovered by looking at the assembler:

When creating a new object a non-zero value is placed in register dl 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 line, 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 it goes wrong, with your code, the compiler sets dl to 1 again before calling Create(True), so on the begin line of TChid_Class.Create(LoadData: boolean);, ClassCreate is called again which results in an AV.

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

My guess is that it is a bug in the Delphi compiler which is fixed in Delphi 2010 and higher.


Partial answer: In your constructor TChid_Class.Create(LoadData: boolean) you are missing 'inherited' in your Create call. This fixes an AV in the example 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;


You are using wrong way to create object! You can't call more than one constructor in one class at creation, but you can only inherite creation. So the right 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;

Reserved word inherited tell to the parent constructor that object is created in child class constructor. Checked under D2007!


This was a compiler bug until the last updates of Delphi 2007.
It works from Delphi 2009 and up.

Renaming the Create function to Initialize solves your problem. It is not only a workaround, but is both correct for fixing the bug, and from a coding perspective:
As a general rule, there should be a clear distinction in the construction and initialization of object instances.

  • Construction should be short, and not raise exceptions.
  • Initialization can take longer and might raise an exception.

--jeroen

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号