Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > ошибка в cоздание своего класса


Автор: blaze 10.2.2006, 07:09
подскажите, в чем ошибка? Создаю свой класс, например в модуле Unit2

Код

TMyClass = class
private
 FData:integer;
public
 Data:integer read FData write FData;
end;


Потом ссылаюсь на этот класс из другого модуля, наприме Unit1, где у меня на нажатие кнопки вызывается

v.data:=123; где v - глобальная переменная в этом модуле тип ее - TMyClass;

После этого события выскакивает Access Violation; Cannot write at adress .....;

Нет Вы не поняли, ошибка возникает при попытке присвоения v.Data:=123
CANNOT WRITE AT ADRESS

Автор: CaNIBaLchik 10.2.2006, 07:15
забыл наверное

v:=TMyClass.Create;

Автор: Bog d`An 10.2.2006, 08:44
после работы тоже неплохо бы освободить память...
Код

...
v.free;
v:=nil;


Автор: Bose 10.2.2006, 10:44
Цитата(Bog d`An @ 10.2.2006, 08:44 Найти цитируемый пост)

...
v.free;
v:=nil;


Код

freeandnil(v);

Автор: Bog d`An 10.2.2006, 13:48
шо в лоб, шо по лбу

Автор: CaNIBaLchik 13.2.2006, 08:14
ага а также destroy
можно dispose тоже сработает smile

Автор: Bog d`An 13.2.2006, 08:24
в литературе рекомендуют использовать free

Автор: CaNIBaLchik 13.2.2006, 08:31
только потому что перед destroy там идет проверка на nil

Автор: s-r 31.5.2007, 08:21
у меня аналогичная ситуация

Код

...
TCirc = class
  private
    cx:integer;
    cy:integer;
    crad:integer;
  public
    procedure SetXY(x: integer; y:integer);
  end;
...
implementation

procedure TCirc.SetXY(x: integer; y:integer);
begin
   cx:=x;  cy:=y;
end;
...




В обработчике по клику:


Код

procedure TForm1.FormClick(Sender: TObject);
var cr:TCirc;
begin
  cr.SetXY(34,34);
end;


код отрабатывает, но после закрытия формы вываливается исключение..

проблема решилась так

Код

procedure TForm1.FormClick(Sender: TObject);
var cr:TCirc;
begin
  cr:=TCirc.Create;
  cr.SetXY(34,34);
end;


Может поскажите какая разница между cr.Create и  cr:=TCirc.Create?
и зачем это нужно делать, и почему если это не сделать возникает ошибка... 

прошу прощения если задаю глупые вопросы

Автор: Yanis 31.5.2007, 08:29
Цитата(s-r @  31.5.2007,  09:21 Найти цитируемый пост)
Может поскажите какая разница между cr.Create и  cr:=TCirc.Create?
и зачем нужно делать, и почему если это не сделать возникает ошибка... 

А такая, что кодом cr.Create ты пытаешься обратиться к свойству объекта который не существует. А кодом cr:=TCirc.Create ты выделяешь память под экземпляр класса TCirc и назначаешь указатель на эту память переменной cr (cr суть указатель).
А зачем так делать, так это ты у борланда спроси. Они так придумали.
Хотя мне такой принцип кажется логичным и прозрачным smile

Автор: MetalFan 31.5.2007, 08:38
можно написать так:
Код

with TCirc.Create do
  SetXY(34, 34 )


хм... как интересно получается... вроде как нельзя обращаться к объекту, который еще не создан.
но ведь такой код является верным:
Код

var
  lObj: TObject;
begin
...
  lObj := nil;
...
  lObj.Free;
...

т.е. во Free произойдет проверка Self <> nil  и выход.
но ведь объект еще не создан/уже разрушен....
или TObject весь такой особенный, что позволяет это делать. или если нет обращения к внутренним полям класса, то вызов методов несозданного объекта все-таки возможен? )))

Автор: Yanis 31.5.2007, 08:45
Цитата(MetalFan @  31.5.2007,  09:38 Найти цитируемый пост)
 lObj := nil;
...
  lObj.Free;

Должна быть ошибка smile

Цитата(MetalFan @  31.5.2007,  09:38 Найти цитируемый пост)
т.е. во Free произойдет проверка Self <> nil  и выход.
но ведь объект еще не создан/уже разрушен....
или TObject весь такой особенный, что позволяет это делать. или если нет обращения к внутренним полям класса, то вызов методов несозданного объекта все-таки возможен? )))

Да, он такой особенный ;)
Не помню как точно называется.
Классовые методы или что то подобное.
Они объявляются так:
Код
class function ClassName: ShortString;

т.е. её можно вызывать без выделения памяти под экземпляр:
Код
  ShowMessage(TObject.ClassName);
  // или
  ShowMessage(c.ClassName);


Вот так работает Create.

Добавлено @ 08:47
Для тех, кто в танке:
Цитата(Help)
Class Methods 
Most methods are called instance methods, because they operate on an individual instance of an object. A class method is a method (other than a constructor) that operates on classes instead of objects. There are two types of class methods: ordinary class methods and class static methods.
 
Ordinary Class Methods 
The definition of a class method must begin with the reserved word class. For example,
Код
 type 
  TFigure = class 
  public 
     class function Supports(Operation: string): Boolean; virtual; 
     class procedure GetInfo(var Info: TFigureInfo); virtual; 
     ... 
  end;
The defining declaration of a class method must also begin with class. For example,
 class procedure TFigure.GetInfo(var Info: TFigureInfo); 
begin 
    ... 
end;

In the defining declaration of a class method, the identifier Self represents the class where the method is called (which could be a descendant of the class in which it is defined). If the method is called in the class C, then Self is of the type class of C. Thus you cannot use the Self to access instance fields, instance properties, and normal (object) methods, but you can use it to call constructors and other class methods, or to access class properties and class fields.
 
A class method can be called through a class reference or an object reference. When it is called through an object reference, the class of the object becomes the value of Self.
 
Class Static Methods 
Like class methods, class static methods can be accessed without an object reference. Unlike ordinary class methods, class static methods have no Self parameter at all. They also cannot access any instance members. (They still have access to class fields, class properties, and class methods.) Also unlike class methods, class static methods cannot be declared virtual. 
Methods are made class static by appending the word static to their declaration, for example 
Код
type
   TMyClass = class
     strict private
       class var
       FX: Integer;
         
     strict protected
    
       // Note: accessors for class properties must be declared class static.
       class function GetX: Integer; static;
       class procedure SetX(val: Integer); static;

     public
       class property X: Integer read GetX write SetX;
       class procedure StatProc(s: String); static;
   end;



Like a class method, you can call a class static method through the class type (i.e. without having an object reference), for example
Код
 TMyClass.X := 17;
TMyClass.StatProc('Hello');

Автор: MetalFan 31.5.2007, 08:53
Free - это не class procedure.... только что посмотрел)
но вызов Free без дополнительной проверки на nil возможен и не приводит к AV....

Автор: Yanis 31.5.2007, 09:08
Цитата(MetalFan @  31.5.2007,  09:53 Найти цитируемый пост)
но вызов Free без дополнительной проверки на nil возможен и не приводит к AV....

Ага.
По всей видимости ошибка начинает возникать после того как в методе начинается работа с переменными класса. Если таковых нет, то всё работает smile
Код
type
  myc = class
    function add(x, y: Integer): Integer;
    function _Div(x, y: Integer): Integer;
  end;

function myc.add(x, y: Integer): Integer;
begin
  Result := x + y;
end;

function myc._Div(x, y: Integer): Integer;
begin
  Result := x div y;
end;

{ … }

var
  c: myc;
begin
  ShowMessage(IntToStr(c.add(1, 2)));
end;

Автор: MetalFan 31.5.2007, 09:19
мда.. а зачем тогда Class functions?... может отдельную тему сказать, вдруг мастера знают секрет этого фокуса? )))

Автор: pseud 31.5.2007, 09:25
Цитата(blaze @  10.2.2006,  07:09 Найти цитируемый пост)
Потом ссылаюсь на этот класс из другого модуля, наприме Unit1, где у меня на нажатие кнопки вызывается

v.data:=123; где v - глобальная переменная в этом модуле тип ее - TMyClass; 

После этого события выскакивает Access Violation; Cannot write at adress .....;

Нет Вы не поняли, ошибка возникает при попытке присвоения v.Data:=123
CANNOT WRITE AT ADRESS 


blaze,

Раз v - глобальная переменная, то в модуле Unit1, как я понимаю это форма TForm1, код должен быть такой:
Код

var
  Form1: TForm1;
  v: TMyClass;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  v := TMyClass.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  v.data:=123;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(v);
end;

Автор: Yanis 31.5.2007, 09:36
Цитата(MetalFan @  31.5.2007,  10:19 Найти цитируемый пост)
мда.. а зачем тогда Class functions?

Тада компилятор не даст нам использовать внутренние переменные в этих методах smile

Добавлено через 6 минут и 38 секунд
Оказывается всё это прокатывает без AV, потому что методы статические. Компилятор их помнит без напоминания.

Спасибо Розычу.

Автор: Alexeis 31.5.2007, 09:49
Цитата(MetalFan @  31.5.2007,  08:53 Найти цитируемый пост)
Free - это не class procedure.... только что посмотрел)
но вызов Free без дополнительной проверки на nil возможен и не приводит к AV....

  А чего в этом такого? С точки зрения реализации метод это обычная процедура в которую первым параметром передается указатель на объект. Если к данным не обращаться, то с чего будут возникать AV? Проверил Self на nil и вперед, если он не nil то VMT существует и можно без проблем вызывать Destroy. Напрямую вызов Destroy, у несуществующего объекта приведет к AV так как Destroy - это виртуальный метод (иногда даже динамический), т.е. поиск его адреса будет осуществляться в VMT, ссылка на которую отсутствует в уничтоженном объекте.

Автор: Yanis 31.5.2007, 09:51
Цитата(Alexeis @  31.5.2007,  10:49 Найти цитируемый пост)
в уничтоженном объекте. 

в несуществующем smile

Добавлено через 18 секунд
или «не созданном».

Автор: Rennigth 31.5.2007, 10:17
Yanis
MetalFan
http://forum.vingrad.ru/forum/topic-115603.html

Автор: Alexeis 31.5.2007, 10:23
Там есть одна неточность 
Цитата(Snowy @  9.10.2006,  10:44 Найти цитируемый пост)
Вызываться функции могут без создания объекта. Любые.

  Уточню, любые статические (статические в делфиском смысле, т.е. не виртуальные и не динамические).

Автор: MetalFan 31.5.2007, 10:46
отлично) разобралис) всем спасибо!

Автор: Yanis 31.5.2007, 14:44
Цитата(Yanis @  31.5.2007,  10:08 Найти цитируемый пост)
По всей видимости ошибка начинает возникать после того как в методе начинается работа с переменными класса. Если таковых нет, то всё работает

 smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)