Модераторы: Snowy, MetalFan, bems, Poseidon

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Работа с объектами, конструкторы и деструкторы 
:(
    Опции темы
boobie
Дата 13.10.2012, 12:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 162
Регистрация: 16.9.2011

Репутация: нет
Всего: нет



Всем доброго времени суток!
Недавно начал знакомство с Delphi, если быть точнее, то с Object Pascal.
Интересует такой момент: поведение объекта при передаче его в процедуру.
Рассмотрим простой пример:
Код

program tt1;
{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;
type c1=class
public
  var i:integer;
  constructor create;
  procedure p();
  destructor destroy;
end;
constructor c1.create;
begin
  writeln('конструктор');
end;
procedure c1.p();
begin
  i:=777;
  writeln('procedure c1.p() ; i=',i);
end;
destructor c1.destroy;
begin
  writeln('деструктор');
end;


procedure n();forward;
procedure n2(rp2:c1);forward;


procedure n2(rp2:c1);
begin
  writeln('в проедуре n2');
  writeln('rp2.i=',rp2.i);
  rp2.i:=555;
  writeln('выходим из процедуры n2');
end;


procedure n();
var
  rp:c1;
begin
  writeln('в процедуре n');
  rp:=c1.Create;
  rp.p();
  n2(rp);
  writeln('опять в процедуре n');
  writeln('rp.i=',rp.i);
  writeln('выходим из процедуры n');
end;

begin
  n();
  readln;
end.

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

procedure n2(var rp2:c1);

или так:
Код

procedure n2(rp2:c1);

результат будет одинаковый. Получается, что Дельфи не копирует объекты, а передает их по ссылке?
Код

program Project1;
{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;
type c1=class
public
  var i:integer;
end;
var global:c1;


procedure n();
var rp:c1;
begin
  writeln('в процедуре n');
  rp:=global;
  writeln(rp.i);
  rp.i:=555;
  writeln('выходим из процедуры n');
end;
begin
  global:=c1.Create;
  global.i:=777;
  n();
  writeln(global.i);
  readln;
end.

Еще один аналогичный пример.

И еще. Деструкторы в Дельфи не вызываются автоматически (например при выходе из процедуры)?

PM   Вверх
DarkProg
Дата 13.10.2012, 12:40 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Законченный романтик
***


Профиль
Группа: Завсегдатай
Сообщений: 1784
Регистрация: 11.3.2009
Где: Земля

Репутация: 4
Всего: 19



Цитата(boobie @  13.10.2012,  13:21 Найти цитируемый пост)
 Получается, что Дельфи не копирует объекты, а передает их по ссылке?

И то и другое умеет делать. Я не понял если честно суть вашего эксперимента.


Цитата(boobie @  13.10.2012,  13:21 Найти цитируемый пост)
еструкторы в Дельфи не вызываются автоматически (например при выходе из процедуры)?

Нет и слава богу. Это же был бы бред...


--------------------
"И твоя голова всегда в ответе за то куда сядет твой зад..."

"Я студент - скажите с какого я ВУЗа..."

 smile  smile  smile 
PM MAIL   Вверх
boobie
Дата 13.10.2012, 13:31 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 162
Регистрация: 16.9.2011

Репутация: нет
Всего: нет



Как работать с копией объекта? Как передать в функцию не ссылку на объект, а его копию? Что тогда произойдет с динамической памятью?
PM   Вверх
DarkProg
Дата 13.10.2012, 14:26 (ссылка)    | (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Законченный романтик
***


Профиль
Группа: Завсегдатай
Сообщений: 1784
Регистрация: 11.3.2009
Где: Земля

Репутация: 4
Всего: 19



Цитата(boobie @  13.10.2012,  14:31 Найти цитируемый пост)
Как работать с копией объекта?

Также.

Цитата(boobie @  13.10.2012,  14:31 Найти цитируемый пост)
Как передать в функцию не ссылку на объект, а его копию?

Передавать не указывая Var или Const, насколько я понимаю работу это и будет копия.


Цитата(boobie @  13.10.2012,  14:31 Найти цитируемый пост)
Что тогда произойдет с динамической памятью? 

Ничего с ней не должно быть, но при многократном выполнении подобной процедуры
Код

 Procedure SomeModification(MyArray:array of SomeType)
 

Есть вероятность и не малая, что произойдёт порча памяти. Нужно обязательно указывать Const или Var.


--------------------
"И твоя голова всегда в ответе за то куда сядет твой зад..."

"Я студент - скажите с какого я ВУЗа..."

 smile  smile  smile 
PM MAIL   Вверх
MetalFan
Дата 13.10.2012, 15:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Цитата(DarkProg @  13.10.2012,  14:26 Найти цитируемый пост)
Передавать не указывая Var или Const, насколько я понимаю работу это и будет копия.

Не путайте людей.

Объект всегда передается по ссылке. Без вариантов.
Копию объекта можно получить, если только предусмотреть для этого функцию типа Clone... в которой будет создан еще один объект и скопированы св-ва исходного.

Это сообщение отредактировал(а) MetalFan - 13.10.2012, 15:19


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
БелАмор
Дата 14.10.2012, 01:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 209
Регистрация: 10.6.2010
Где: Россия

Репутация: 7
Всего: 17



Цитата(boobie @  13.10.2012,  13:21 Найти цитируемый пост)
Недавно начал знакомство с Delphi, если быть точнее, то с Object Pascal.

Начиная с Delphi 7, язык Object Pascal стал называться так-же, как и среда разработки: Delphi.

Цитата(boobie @  13.10.2012,  13:21 Найти цитируемый пост)
type c1=class
public
  var i:integer;


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

Насколько я понял, вы имеете опыт работы с С++. Когда я после C++ занялся изучением Delphi, я испытал культурный шок. В такой ситуации важно понять, что есть просто разные подходы, и все они имеют право на жизнь. И переходя в другую систему координат, нужно просто действовать в соотвествии с правилами, принятыми в этой ситеме. Остальное - дело привычки. Например, я некоторое время продолжал писать пустые скобки у функций при отутствии параметров, избегал пользоваться фигурными скобками для комментариев и т.д. Исходя из своего опыта в сходной ситуации, я позволю себе дать несколько комментариев на эту тему.

Цитата(boobie @  13.10.2012,  13:21 Найти цитируемый пост)
  procedure p();

В Delphi при отсутствии параметров как при объявлении, так и при вызове, скобки принято не писать. Первоначально это воспринимается как ломка устоявшихся привычек, однако, со временем понимаешь, что никаких особых проблем это не вызывает.

В Delphi очень много подразумеваемых умолчаний.
Одно из них:
Все переменные классового типа являются указателями.

Если в C++ есть два сполоба объявления:

Код

  TSomeClass SomeObject;   // (1)   SomeObject - объект
  TSomeClass *SomeObject;  // (2)   SomeObject - указатель


то в Delphi есть только один:

Код

  SomeObject: TSomeClass;   // (3)   SomeObject - указатель


При этом объявление (3) эквивалентно объявлению (2), т.е. SomeObject, хотя и не объявлен явно как указатель, является именно указателем. Зная это, вы можете логическим путём сделать все необходимые выводы.
Полного эквивалента варианту объявления (1) в Delphi нет. Нечто похожее можно изобразить в новых версиях Delphi, в которых структура (record) может иметь методы, однако там есть куча ограничений и не следует пытаться заменить класс структурой просто из желания получить аналог объявления (1).
Привыкнете к тому, что в Delphi всегда следует явно вызывать конструктор и деструктор (кроме случаев удаления компонента его владельцем или родителем).
Заодно замечу, что в Delphi принято вызывать деструктор не напрямую, а через метод Free. Лично я считаю эту традицию крайне вредной, но идти против толпы не хочется.

PM   Вверх
boobie
Дата 14.10.2012, 06:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 162
Регистрация: 16.9.2011

Репутация: нет
Всего: нет



Спасибо, теперь все понятно.
PM   Вверх
lomaster
Дата 14.10.2012, 16:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 101
Регистрация: 27.5.2012

Репутация: нет
Всего: 2



Цитата

Объект всегда передается по ссылке. Без вариантов.
 И вы не путайте. Одно дело по ссылке, и другое сама ссылка.

Цитата

Все переменные классового типа являются указателями.
 Ссылками.
PM   Вверх
MetalFan
Дата 14.10.2012, 16:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Цитата(lomaster @  14.10.2012,  16:17 Найти цитируемый пост)
Одно дело по ссылке, и другое сама ссылка.

И в чем разница? ну-ка просветите ка нас всех.  желательно с примерами, демонстрирующими разницу.
Цитата(lomaster @  14.10.2012,  16:17 Найти цитируемый пост)
Ссылками. 

ccылка=указатель, разве нет?

Добавлено @ 16:50
Цитата(БелАмор @  14.10.2012,  01:00 Найти цитируемый пост)
В объявлении класса не следует использовать ключевое слово var (кроме случаев, когда вы действительно хорошо знаете, что делаете). C var объявляется (если ничего не путаю) статическое поле (одно общее на все экземпляры класса), что требуется крайне редко.

Путаешь. поле, общее для всех объектов описываемого  класса объявляется с помощью class var.
Никакого криминала в этом нет, вполне нормальное объявление:
Код

TSomeObject = class
  ...
  public
    FField1: sometype;
    function Func(AParam: paramtype): resulttype;
  ...
  var
    FField2: sometype2;
  ...
end; //TSomeObject

Цитата(БелАмор @  14.10.2012,  01:00 Найти цитируемый пост)
Лично я считаю эту традицию крайне вредной

Обоснуй плиз, интересно.
Просто вывзов Free ограждает пользователя объекта от необходимости проверки на nil переменной, содержащей ссылку на объект.

Это сообщение отредактировал(а) MetalFan - 14.10.2012, 16:54


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
БелАмор
Дата 15.10.2012, 00:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 209
Регистрация: 10.6.2010
Где: Россия

Репутация: 7
Всего: 17



Цитата(MetalFan @  14.10.2012,  17:46 Найти цитируемый пост)
Путаешь. поле, общее для всех объектов описываемого  класса объявляется с помощью class var.

Да, спасибо за поправку. Не стал уточнять в хелпе, потому и сделал оговорку по поводу "если ничего не путаю". Оказалось, не зря.

Цитата(MetalFan @  14.10.2012,  17:46 Найти цитируемый пост)
Никакого криминала в этом нет

Но и смысла в этом тоже никакого нет.
Использовать var в объявлении класса имеет смысл только для явного прерывания секции class var (которая прерывается с появлением метода, свойства, ключевого слова var, или спецификатора видимости). Например, так:

Код

TSomeObject = class
  public
  class var  
    FField1: sometype1;
    FField2: sometype2;
  var
    FField3: sometype3;
  ...
end;


Цитата(MetalFan @  14.10.2012,  17:46 Найти цитируемый пост)
Обоснуй плиз, интересно.
Просто вывзов Free ограждает пользователя объекта от необходимости проверки на nil переменной, содержащей ссылку на объект.


А теперь прикинем, когда переменная может иметь значение nil:
1. Ей не присваивалось значение и это не локальная переменная.
2. Объект удалили и ссылку принудительно обнулили.

Free используют постоянно, а часто ли обнуляют ссылки? При необнулении ссылок использование Free преврвщается в профанацию: Free не защищает ни от чего, даже просто от повторного вызова Free. Но у новичков в голове откладывается фраза "безопасное удаление" и приводит к непониманию ситуации и дальнейшим ошибкам.
С непониманием этого момента приходится сталкиваться постоянно и давать пояснения вроде таких:
http://www.delphikingdom.com/asp/answer.asp?IDAnswer=57952

Некоторые считают, что лучше всегда использовать FreeAndNil вместо Free. Апологетом такого подхода является, например, Александр Алексеев:
http://www.gunsmoker.ru/2009/04/freeandnil-free.html
Этот подход значительно более логичен, чем распространённая практика.

Лично я считал бы правильным повседневно использовать Destroy, а при необходимости проверки на не-nil (а коли нужна проверка, то тут и обнуление в комплекте) - FreeAndNil. Однако объяснять каждый раз "почему Destroy, а не Free" - неэффективная трата времени. Поэтому я таки повседневно использую Free как дань традиции, а FreeAndNil - когда надо ещё и обнулить ссылку.

PM   Вверх
northener
Дата 15.10.2012, 00:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1361
Регистрация: 2.9.2010

Репутация: 12
Всего: 20



Цитата(БелАмор @  15.10.2012,  00:03 Найти цитируемый пост)
Некоторые считают, что лучше всегда использовать FreeAndNil вместо Free.

И я тоже.

P.S. 
Я только не понимаю причины, которые заставляют авторов ПО многократно использовать некоторую переменную для хранения ссылок на некоторый класс(форму), который многократно создают и уничтожают в течение работы программы.


--------------------
Но только лошади летают вдохновенно.
Иначе лошади разбились бы мгновенно!
PM MAIL   Вверх
northener
Дата 15.10.2012, 01:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1361
Регистрация: 2.9.2010

Репутация: 12
Всего: 20



Цитата(БелАмор @  15.10.2012,  00:03 Найти цитируемый пост)
Лично я считал бы правильным повседневно использовать Destroy

А что ты скажешь о методе Release?


--------------------
Но только лошади летают вдохновенно.
Иначе лошади разбились бы мгновенно!
PM MAIL   Вверх
MetalFan
Дата 15.10.2012, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Цитата(northener @  15.10.2012,  01:41 Найти цитируемый пост)
А что ты скажешь о методе Release? 

Так это актуально только для форм... да и то имеет свои особенности, о которых не стоит забывать...


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
DarkProg
Дата 15.10.2012, 10:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Законченный романтик
***


Профиль
Группа: Завсегдатай
Сообщений: 1784
Регистрация: 11.3.2009
Где: Земля

Репутация: 4
Всего: 19



Цитата(northener @  15.10.2012,  01:57 Найти цитируемый пост)
Я только не понимаю причины, которые заставляют авторов ПО многократно использовать некоторую переменную для хранения ссылок на некоторый класс(форму), который многократно создают и уничтожают в течение работы программы. 

Ну надо смотреть от ситуации, но вот сделать типа такого: 
1. Чего-то создать
2. Чего-то сделать
3. Разрушить это чего-то
4. Повторять пока не наступит что-то там

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

Хотя есть ситуации когда надо именно разрушать объект. Иногда из-за некоторой ограниченности алгоритма или из-за принципа "надо здесь и сейчас и пофиг, что работает медленно".


--------------------
"И твоя голова всегда в ответе за то куда сядет твой зад..."

"Я студент - скажите с какого я ВУЗа..."

 smile  smile  smile 
PM MAIL   Вверх
БелАмор
Дата 15.10.2012, 21:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 209
Регистрация: 10.6.2010
Где: Россия

Репутация: 7
Всего: 17



Цитата(northener @  15.10.2012,  02:41 Найти цитируемый пост)
А что ты скажешь о методе Release?

Как тут уже упомянули, Release - это весьма частный случай, поскольку:

1. Применим только к формам.
2. Имеет смысл применять только к немодальным формам, в первую очередь MDIChild.

По поводу Release, а также некоторым рядом лежащим вопросам (и не только) можно почитать по ссылке:
http://forum.vingrad.ru/act-ST/f-331/t-308242.html

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


Это сообщение отредактировал(а) БелАмор - 15.10.2012, 21:42
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0693 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.