Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.05.20;
Скачать: CL | DM;

Вниз

Object constructors? Very interesting! :)   Найти похожие ветки 

 
maxnovikov ©   (2002-04-11 07:40) [0]

Здравствуйте!

Вот есть такой код:



T = class
protected
m_i : integer;
public
constructor Create;
//begin
// m_i := 100;
//end;
end;

...
procedure TForm1.Button1Click(Sender: TObject);
var
p : T;
t : T;
begin
p := T.Create;
p.m_i := 5;

t := p.Create;
t.m_i := 3;

p.Free;
t.Free;
end;


Что должно получиться, если попытаться откомпилить/запустить
этот код?

Спасибо.


 
maxnovikov ©   (2002-04-11 07:45) [1]

Прошу прощения,
там тип T и переменная t получились одноименные.
Можно исправить что-нибудь (для уникальности имен).


 
MBo ©   (2002-04-11 07:46) [2]

К чему такой вопрос?
Если T объявлен в одном модуле с формой, все работать будет.
Иначе не скомпилируется.


 
Внук ©   (2002-04-11 09:13) [3]

>>MBo © "К чему такой вопрос?"
Наверное, к тому, что
p := T.Create;
t := p.Create;
Конструктор неявно считается методом класса (class method), а не обычным методом. Вероятно, вопрошающий хотел услышать, что не возбраняется вызывать методы класса через ссылку на экземпляр этого класса, а не только через имя этого класса? До сих пор жалею, что в Delphi не реализованы переменные класса, что им стоило :)


 
Anatoly Podgoretsky ©   (2002-04-11 09:29) [4]

Так можно t := p.Create; но этого стоит избегать, p может быть не создано.


 
MBo ©   (2002-04-11 09:51) [5]

>p := T.Create;
>t := p.Create
аaa, я не уловил, посчитал за описку, как с t- и тип и var


 
Бурундук   (2002-04-11 10:54) [6]

>Что должно получиться, если попытаться откомпилить/запустить
>этот код?

АксессВайолэйшн, естественно - ты же два раза освобождаешь один и тот же объект.

PS Ещё один довод против вызывания конструктора как метода - если
конструкторе создаются другие объекты, будет утечка памяти
(они будут пересозданы, а ссылки на старые экземпляры потеряны)


 
Shaman_Naydak ©   (2002-04-11 11:06) [7]

Бурундук прав, во втором вызове (как метода) произойдет просто переинициализация (без повторного выделения памяти того же объекта, обе переменные будут указывать на один и тот же объект, как следствие чего на втором освобождении будет Access Violation

Я с VUK"ом уже подробно разбирались с этой байдой на
http://delphi.mastak.ru/cgi-bin/forum.pl?look=1&id=1015408187&n=3


 
Anatoly Podgoretsky ©   (2002-04-11 11:13) [8]

C какой стати, Create возвращает адреч, который присваивается другой переменно1


 
Внук ©   (2002-04-11 14:43) [9]

Мне тоже не верится. В чем разница, если конструктор вызван через ссылку на объект, или через имя класса? Должно быть по барабану. Сейчас попробую :)


 
Внук ©   (2002-04-11 15:48) [10]

Эврика! То есть, нашел :)) Действительно, не работает.
Пишем код:

procedure TForm1.Button1Click(Sender: TObject);
var c1,c2:TStringList;
begin
c1:=TStringList.Create;
c2:=nil;
c2:=c1.Create;
ShowMessage(IntToStr(Integer(@c1)));
ShowMessage(IntToStr(Integer(@c2))); // адреса здесь разные получаются
c1.Free;
c1:=nil;
if Assigned(c2) then c2.Free; // Invalid Pointer Operation
end;
Обидно и непонятно, от этого еще обиднее :) Читаем Help:

To create an object, call the constructor method in a class type. For example,

MyObject := TMyClass.Create;

This allocates storage for the new object on the heap, sets the values of all ordinal fields to zero, assigns nil to all pointer and class-type fields, and makes all string fields empty. Other actions specified in the constructor implementation are performed next; typically, objects are initialized based on values passed as parameters to the constructor. Finally, the constructor returns a reference to the newly allocated and initialized object. The type of the returned value is the same as the class type specified in the constructor call.
...
When a constructor is called using an object reference (rather than a class reference), it does not create an object or return a value. Instead, the constructor operates on the specified object, executing only the statements in the constructor’s implementation.

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

TTest=class
public
i:integer;
constructor Create;
end;

constructor TTest.Create;
begin
i:=3;
end;

procedure TForm1.Button2Click(Sender: TObject);
var m:TTest;
begin
m:=TTest.Create;
ShowMessage(IntToStr(m.i)); //Выводит 3
m.i:=5;
ShowMessage(IntToStr(m.i)); //Выводит 5
m.Create;
ShowMessage(IntToStr(m.i)); //Выводит 3
m.Free; // Завершается без ошибок !!!
end;

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


 
Бурундук   (2002-04-11 16:57) [11]

2Внук - проснись.
Сравнивать надо Pointer(c1) и Pointer(c2) - и они таки равны.


 
Внук ©   (2002-04-12 09:36) [12]

>>Бурундук (11.04.02 16:57)
Действительно, тормознул, надо
ShowMessage(IntToStr(Integer(с1)));
ShowMessage(IntToStr(Integer(c2)));
Но если они у Вас равны, то это случайность, у меня это через раз. Повторяю: "When a constructor is called using an object reference (rather than a class reference), IT DOES NOT create an object or RETURN A VALUE". Будем спорить с Delphi Help? Это не ко мне :)



Страницы: 1 вся ветка

Текущий архив: 2002.05.20;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.013 c
1-64674
HDD
2002-05-05 04:59
2002.05.20
Помогите пожалуйста!


14-64823
DeMoN-777
2002-04-11 04:15
2002.05.20
Чем С++ лучше Delphi ?


14-64833
Oleh
2002-04-12 11:37
2002.05.20
Динамическиє собития


3-64513
s
2002-04-23 11:54
2002.05.20
Упаковка базы данных


4-64885
Gayrus
2002-03-17 14:06
2002.05.20
Папки