проблема с функцией с именем создать в Delphi - PullRequest
5 голосов
/ 15 декабря 2010

у меня есть базовый класс, объявленный следующим образом

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

Теперь в другом модуле существует дочерний класс TChid_Class, который происходит от 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;

в этом классе.Функция называется Create, как и конструкторы, проблема в том, что когда я пытаюсь создать экземпляр для TChid_Class, у меня есть нарушение прав доступа.

я написал это небольшое консольное приложение, в котором показана проблема

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.

если я переименую функцию create, проблема исчезнет, ​​но я ищу решение без переименования функции createили конструкторы.

с использованием delphi 2007

Заранее спасибо.

Ответы [ 4 ]

4 голосов
/ 15 декабря 2010

С Delphi 7 я тоже получаю AV. Переименование метода или его перемещение (согласно предложению Сертака Акьюза) исправляет AV.

Что я обнаружил, глядя на ассемблер:

При создании нового объекта ненулевое значение помещается в регистр dl перед вызовом конструктора.

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

Затем в конструкторе в строке begin вызывается ClassCreate, когда dl не равен нулю.

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

Но тогда с вашим кодом компилятор снова устанавливает dl в 1, прежде чем вызвать Create(True), поэтому в строке begin TChid_Class.Create(LoadData: boolean); снова вызывается ClassCreate, что приводит к AV.

После переименования вашей функции или перемещения ее объявления компилятор очищает dl (xor edx,edx) вместо того, чтобы установить его в 1, перед вызовом Create(True).

Я предполагаю, что это ошибка в компиляторе Delphi, исправленная в Delphi 2010 и более поздних версиях.

2 голосов
/ 15 декабря 2010

Частичный ответ : В вашем конструкторе TChid_Class.Create (LoadData: boolean) вам не хватает «унаследованных» в вызове Create.Это исправляет AV в примере кода, если вы вызываете * TChid_Class.Create (True) * в вашем демонстрационном проекте.

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;
1 голос
/ 15 декабря 2010

Вы используете неправильный способ создания объекта! Вы не можете вызывать более одного конструктора в одном классе при создании, но вы можете только наследовать создание . Так что правильный путь - это что-то вроде:

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;

Зарезервированное слово , унаследованное , сообщает родительскому конструктору, что объект создан в конструкторе дочернего класса. Проверено под D2007!

0 голосов
/ 16 декабря 2010

Это была ошибка компилятора до последних обновлений Delphi 2007.
Работает с Delphi 2009 и выше.

Переименование функции Create в Initialize решает вашу проблему. Это не только обходной путь, но это верно и для исправления ошибки, и с точки зрения кодирования:
Как правило, должно быть четкое различие в построении и инициализации экземпляров объекта.

  • Конструкция должна быть короткой, а не вызывать исключения.
  • Инициализация может занять больше времени и может вызвать исключение.

- Йерун

...