Класс не работает, когда он определен как глобальная переменная в Delphi - PullRequest
1 голос
/ 15 февраля 2012

Я создал простой класс, чтобы объяснить мою проблему:

ttest =class
private
   val:boolean;
published
   function get:boolean;
end;

...

function ttest.get: boolean;
begin
   val:=not val;
   result:=val;
end;

Теперь, если я объявлю локальную переменную ttest и вызову my_var.get; тогда все работает, но если я объявляю его как глобальную переменную, он больше не может получить доступ к полю val, он показывает сообщение об ошибке, которое говорит: «Нарушение доступа ...». Я прочитал несколько статей о занятиях в Delphi, но все еще не могу найти свою ошибку.

Ответы [ 3 ]

5 голосов
/ 15 февраля 2012

Вы пренебрегли созданием класса.

Глобальные переменные-ссылки на класс инициализируются в nil, тогда как локальные переменные не инициализируются вообще.Локальная переменная имеет значение, определяемое тем, что было в стеке в тот момент, когда вы вызывали свою функцию, и ваша программа интерпретирует это значение, как если бы оно было ссылкой TTest, хотя на самом деле это не так.Затем ваша программа считывает значение по этому адресу памяти, чтобы получить значение, которое будет представлять поле val.

Единственная причина, по которой ваш код работает с неглобальной переменной - это удача.Хорошо это или плохо - другое дело.(Удачи, поскольку ваш код, казалось, работает, а рабочий код всегда хорош. Не повезло, так как вы были бы предупреждены о своей ошибке ранее, если ваш код потерпел крах.)

Создайте класс перед вамииспользуйте ссылки на него.

x := TTest.Create;

Теперь вы можете получить доступ к полям, методам и свойствам объекта через переменную x.

Вы должны были получить предупреждение компилятора когда вы пытались использовать локальную переменную без предварительного присвоения ей значения.Хотя это всего лишь предупреждения, и ваша программа все равно будет работать, никогда не игнорируйте предупреждение или даже подсказку.Когда компилятор жалуется на что-то, это обычно правильно.

3 голосов
/ 15 февраля 2012

В Delphi переменные объекта всегда указатели.Прежде чем вы сможете использовать переменную, вам нужно инициализировать ее ссылкой на объект.Наиболее распространенный способ сделать это - создать новый объект определенного класса.

procedure Foo;
var
  Obj: TObject;
begin
  Obj := TObject.Create;
  try
    // Do stuff with Obj
  finally
    Obj.Free;
  end;
end;

В этом случае Obj начинается как неинициализированный указатель (он указывает на случайную память).Только после того, как мы присваиваем вновь созданный объект TObject, Obj является допустимой ссылкой на объект.

В Delphi нет автоматической сборки мусора для объектов, поэтому вам всегда нужно вызывать free для них, когда вы закончите с их использованием.,Если вы объявляете глобальную или локальную переменную объекта, вы можете инициализировать ее в специальном разделе инициализации модуля и освободить объект в разделе завершения.

unit myunit;

interface

var
  Obj: TObject;

implementation

initialization

Obj := TObject.Create;

finalization

Obj.Free;

end.

Переменные, объявленные в разделе интерфейса, являются глобально видимыми, переменныезаявленные в разделе реализации видны только внутри блока.Следует отметить, что объявление переменной глобального объекта означает, что любой модуль может перезаписать переменную ссылкой на новый объект, не освобождая при этом существующий объект.Это может привести к утечке памяти, так как опять нет автоматической сборки мусора.

0 голосов
/ 15 февраля 2012

Класс delphi - это просто описание, а не сам объект. Вы описываете свойства и методы, которые должен иметь конечный объект. И недостающий фрагмент головоломки состоит в том, что вы действительно не сказали Delphi создать объект из вашего класса.

Это делается путем вызова конструктора:

mMyInstance:=TTest.Create;

Конструктор берет описание класса и создает для вас экземпляр объекта в памяти. Он возвращает указатель на объект, который необходимо сохранить в переменной (myInstance в приведенном выше примере) того же типа.

Читая ваш вопрос, я подозреваю, что вы хотите создать объект, который "всегда рядом", немного похож на объект принтера. Это легко сделать, но так же, как объект принтера - вы должны включить этот блок, прежде чем вы получите доступ к объекту. Я думаю, что Андерс Э. Андерсен выше показал, как большинство людей инициализируют объект с единичной точки зрения.

Если вы хотите, чтобы объект был доступен из другого устройства, например, из основной формы или любого другого объекта, сначала добавьте «myunit» в список использований. Затем, чтобы сделать его видимым, вы добавляете функцию, например так:

function test:ttest;
Begin
  result:=obj;
end;

И не забудьте добавить «функциональный тест: TTest» в интерфейсную часть устройства. Тогда вы можете использовать объект из другого подразделения как таковой:

myUnit.test.get;

Но будьте осторожны! Это довольно старое школьное программирование, и вы рискуете выпустить ваш юнит (который вызывает финализацию и, следовательно, уничтожает ваш объект), прежде чем другие юниты покончат с ним. Таким образом, вы рискуете вызвать функцию в объекте, которого больше нет в памяти, и вызвать эффектное нарушение доступа при закрытии вашей программы.

Если вы хотите изучать Delphi правильно, перейдите к Основы Delphi и ознакомьтесь с основными принципами. Для изучения нового языка требуется некоторое время, но вскоре вы освоите его.

Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...