Форум: "Потрепаться";
Текущий архив: 2002.05.20;
Скачать: [xml.tar.bz2];
Вниз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;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.006 c