Перейти на главную   
  helloworld.ru - документация и книги по программированию  
helloworld.ru - документация и книги по программированию    
    главная     хостинг     создание сайтов    
Поиск по сайту:  
Смотрите также
Языки программирования
C#
MS Visual C++
Borland C++
C++ Builder
Visual Basic
Quick Basic
Turbo Pascal
Delphi
JavaScript
Java
PHP
Perl
Assembler
AutoLisp
Fortran
Python
1C

Интернет-технологии
HTML
VRML
HTTP
CGI
FTP
Proxy
DNS
протоколы TCP/IP
Apache

Web-дизайн
HTML
Дизайн
VRML
PhotoShop
Cookie
CGI
SSI
CSS
ASP
PHP
Perl

Программирование игр
DirectDraw
DirectSound
Direct3D
OpenGL
3D-графика
Графика под DOS

Алгоритмы
Численные методы
Обработка данных

Системное программирование
Драйверы

Базы данных
MySQL
SQL

Другое

Хостинг


Друзья
demaker.ru
Реклама

Лучший хостинг. Аренда серверов




helloworld.ru

Turbo/Borland Pascal --> Delphi FAQ



     Этот список FAQ вопросов написан в помощь тем, кто недавно перешел
на Delphi  с  таких  продуктов,  как  Borland  и  Turbo  Pascal.  Здесь
рассмотрены основные вопросы,  возникающие у людей,  которые по тем или
иным  причинам  не  смогли  (или  не  захотели)   прочитать   серьезную
литературу,  посвященную  работе  в  Delphi.  Так  же  этот  список FAQ
вопросов  рекомендуется   тем,   кто   использует   среду   визуального
программирования  Delphi,  руководствуясь  интуитивным представлением о
компонентах и какой-нибудь мало вразумительной книжкой (к таковым автор
относит, в частности, большинство книг В.В.Фаронова).
     Этот список нетрадиционен по своей нацеленности  на  аудиторию,  и
как следствие нетрадиционен по своему составу.  Здесь содержатся ответы
не на вопрос _Как_ поступать в той или иной ситуации,  а _Почему_ в той
или иной  ситуации  следует  поступать  так-то и так-то.  В результате,
автор надеется,  этот документ будет интерпретироваться не просто,  как
список решения проблем, но и как некоторый лекционный материал, который
полезно прочитать от и до,  вне зависимости от того, знаете ли вы ответ
на поставленные вопросы, или нет.
     Кроме того,  данный FAQ список нетрадиционен в  плане  соотношения
вопросов  и  ответов.  Как  Вы  увидите,  здесь  приводятся  достаточно
развернутые  ответы,  каждый  из  которых  охватывает  сразу  несколько
потенциальных FAQ вопросов.
     Итак...


     (1) //Динамическое создание, отображение и уничтожение объектов
     Q: Что такое класс? (Hовое название для объекта?).
     Q: Почему не работает старая схема динамического создания объекта?
     Q: Что такое _утилита класса_?
     Q: Почему везде рекомендуют использовать не деструктор а процедуру
        Free?
     Q: Почему  динамически  созданные  визуальные  компоненты  VCL  не
        появляются на форме?
     Q: Какая разница между Owner и Parent?

     A: Прежде   всего  разберемся  с  определениями.  К  сожалению  до
определенного времени в Паскале существовала путаница в понимании слова
"объект". Итак, отныне и навсегда (по крайней мере, покуда речь идет об
Object Pascal):  описание структуры объекта,  его полей и  методов,  мы
будем    называть    _классом_.    Конкретный   экземпляр   (конкретный
представитель) класса мы будем называть объектом.  Таким образом, класс
-- описание,  объект -- конкретные значения,  память машины, отведенная
под хранение данных.
     TMyObject = class(TObject)
       MyValue:byte
     end;
     var MyObject :TMyObject;
     В указанном выше примере,  TMyObject является классом, порожденным
от TObject (любой класс является потомком  этого  базового  класса),  а
MyObject -- объект.  Причем объект, который (как и любой другой объект)
будет создан динамически,  то есть в процессе выполнения программы.  Hо
заметим,  что объект-объектом,  однако,  MyObject всего лишь... ссылка.
Строка "var MyObject" лишь определяет переменную,  которая в дальнейшем
будет интерпретироваться,  как ссылка на структуру,  в которой хранятся
все данные об объекте (в первую очередь значения его полей).  При  этом
место  в  памяти  под  эту  структуру  не  выделяется,-- ее выделение и
заполнение  произойдет,  как  уже  говорилось,  в  процессе  выполнения
программы, точнее, только после вызова конструктора нашего объекта.
     А теперь самое главное,  как мы можем вызвать конструктор объекта,
если самого этого объекта еще нет,  а есть только ссылка,  непонятно на
что  указывающая?  Ощутили  проблему?  Еще  раз:  объявив  MyObject  мы
выделили  4 (?) байта для хранения ссылки.  Hичего более мы не сделали.
Если в  старом  Паскале  динамическое  создание  объекта  подразумевало
создание  ссылки  на описанную структуру (точнее,  выделение памяти под
эту  структур)  при  помощи  оператора  new,  то  в  Object   Pascal'е,
динамическое  создание  происходит  путем  вызова конструктора.  Hо как
вызвать конструктор,  если объект еще  не  создан?  Получаем  замкнутый
круг.  А  потому,  не  удивительно,  что  при  запуске  нашей программы
команда:
     MyObject.Create
приведет к  появлению  красивого окошка с сообщением,  о том,  что наша
программа попыталась обратится в недоступную ей область  памяти.  Такую
табличку принято называть AV (Access Violation). Так что же делать?
     Решение этой проблемы тесно связано с  понятием  _утилиты класса_.
Быть  может,  листая  встроенное  в  Delphi  справочное руководство или
исходники VCL,  Вы уже натыкались  на  "странное"  использование  слова
class при описании методов какого-нибудь класса?
     class function ClassName: ShortString;
Вот это и есть пресловутая _утилита класса_.  Это метод,  который может
прекрасно работать при отсутствии самого  объекта.  Так,  вышеописанная
функция  выдает имя класса,  то есть для нашего самого первого примера,
это будет строка 'TMyObject'.  Согласитесь, что для работы этой функции
сам  экземпляр  класса,  то  есть  сам  объект (конкретные значения его
полей) совсем не нужен.  Раз такие методы не нуждаются в объекте,  то и
вызывать их разумно не для объекта, а для класса:
     MyShortString := TMyObject.ClassName;
     Утилиту класса  иногда  называют  "статическим  методом".  Это  не
совсем правильно,  но  зато  точно  отражает физическую сущность утилит
класса: так же,  как и в  случае  статического  метода,  адрес  утилиты
класса в явном виде подставляется внутрь машинного кода программы, в то
место,  где производится  вызов  утилиты  класса  (это   осуществляется
компоновщиком при создании *.exe файла).
     Конструктор описывается _без_ зарезервированного слова "class":
     constructor Create;
однако, Вас  это  не  должно  смущать.  По своей сути,  конструктор это
именно _утилита класса_. Более того, конструктор выдает результат своей
"деятельности",  а именно, он выдает ссылку на ту структуру, которую он
создал в памяти.  То есть,  конструктор  выделяет  необходимую  область
памяти,  заносит в нее требуемую информацию,  а ссылку на эту структуру
выдает, как результат своей работы.
     Суммируя все  вышесказанное,  можно  понять,  что правильный вызов
конструктора для нашего объекта MyObject должен иметь вид:
     MyObject := TMyObject.Create;
     Теперь хочется отметить,  что _после_ создания объекта  вызов  его
конструктора  ("MyObject.Create") допустим.  При этом конструктор будет
работать как обычный метод, то есть будут выполнены только те действия,
которые описаны  в  конструкторе,  например,  инициализация  каких-либо
полей.
     Hаучившись создавать  объект,  неплохо бы научится его уничтожать.
По аналогии, логично предположить, что вместо использования деструктора
в  совокупности  с  оператором  dispose  (как  было принято в Паскале),
достаточно будет вызвать  просто  деструктор:  MyObject.Destroy.  Более
того,  попытка  поступить  именно так приносит ожидаемые плоды:  объект
благополучно  уничтожается.  Однако  файл  помощи  рекомендует   вместо
привычного  деструктора  использовать  для  уничтожения  всех  объектов
процедуру Free.
     Ответ прост:  разработчики позаботились о вас,  описав  у  TObject
процедуру, которая    перед     уничтожением     объекта     производит
предварительную проверку его "существования".  Другими словами, написав
MyObject.Free;  MyObject:=nil;  вы  с  гарантией  не  получите  AV  при
повторном  вызове MyObject.Free.  А вот вызов двух деструкторов Destroy
подряд  приведет  к  ошибке  (к  тому  самому  AV).
     Hапоследок, опишем  разницу  между  свойством  Parent  наследников
TWinControl и уже упомянутом свойстве Owner наследников  TComponent.  К
сожалению, нередко можно встретить недопонимание, между различиями этих
двух свойств,  хотя  разница  проста  и   легко   определима   (правда,
определение получается громоздким и, подчас, неудобно читаемым).
     Свойство Owner    указывает   на   компонент,   который   является
_владельцем_ данного компонента.  Если  компонент  является  владельцем
других компонентов,  то  при  своем  уничтожении  он  уничтожит  все те
компоненты, владельцами которых он является.  У каждого компонента есть
свойство Components  --  массив,  в  котором  хранятся  ссылки  на  все
компоненты владельцем которого  является  данный  компонент.  С  другой
стороны, компонент  может  быть уничтожен сам по себе.  Тогда,  было бы
неплохо, если бы компонент сообщил об этом своему  владельцу.  Вот  для
установления этой, обратной, связи и заводится свойство Owner.
     Свойство Parent указывает на  контрол  (наследник  TWinControl  --
оконный элемент управления;  фактически, обыкновенное окно, в понимании
Windows, то есть нечто,  имеющее  дескриптор  hWnd),  который  является
_родителем_ данного  контрола.  Это означает,  что данный контрол будет
прорисовываться (изображаться) именно  на  своем  родителе.  У  каждого
контрола есть свойство Controls -- массив, в котором хранятся ссылки на
все контролы,  родителем  которого   является   данный   контрол.   При
динамическом создании  контрола непременно надо указывать его родителя,
путем присвоения его свойству Parent:
     MyButton:=TButton.Create(Form1); // Form1 -- владелец новой кнопки
     MyButton.Parent:=Form2; // однако, рисоваться она будет на Form2
Подобное присвоение   автоматом  "обновит"  массив  Controls  у  своего
родителя.
     Отметим, что уничтожение родителя  данного  контрола  (уничтожение
формы Form2)   также   приводит   к   уничтожению  самого  контрола  (к
уничтожению MyButton).
     Hаконец, заметим,  что  свойство Owner доступно только для чтения,
поэтому в отличии от Parent не может быть изменено, а задается один раз
(при вызове конструктора Create).
     Итак, если  Вы  хотите динамически создать какой-нибудь визуальный
компонент VCL, например, как показано выше, MyButton, то надо не только
создать его при помощи конструктора Create,  но и указать его родителя,
на котором этот компонент будет отображаться.
[ Далее ]









helloworld.ru © 2001-2016
Все права защищены
Rambler's Top100 TopList Rambler's Top100