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
精彩评论