Private — Директива Delphi


Содержание

Private — Директива Delphi

Наверняка, в предыдущих уроках вы задавались вопросом: что же обозначает ключевое слово public в описании класса? Именно об этом мы сейчас и поговорим.
Но сначала мы вернемся к истокам объекто-ориентированного программирования, а вернее к тем парадигмам, которые лежат в основе ООП. Одной из наиболее важных целей ООП является возможность отделить внутреннюю реализацию класса от внешнего использования и реализовывать класс так, чтобы он выполнял только строго задуманную задачу. При этом необходимо отделить реализацию задуманной задачи в классе от возможностей внешнего использования этого класса. Такой подход называется инкапсуляцией. Это такой механизм ООП, который позволяет ограничить доступ к составляющим класса (методам и полям. И необходимо его использовать для того, чтобы, к примеру, ограничить внешний доступ к каким-либо составляющим класса, которые обеспечивают внутреннюю реализацию самого класса. Т.е. те методы и поля, которые использовать извне не рекомендуется, которые служат для внутреннего функционирования, работы класса, будет грамотнее сделать недоступными для обращения из внешнего кода класса. Внешним кодом для класса в данном случае мы называем код, который не является реализацией данного класса. Ранее мы видели подобную конструкцию:
[cc lang=»delphi»]TTeacher = class
public
FullName: string;

constructor Create(NewFullName: string);
destructor Destroy;
end;[/cc]

Ключевое слово public указывает на то, что последующие поля и методы будут доступны во внешнем коде у данного класса. Т.е. все, что следует после public будет доступно отовсюду при обращении к экземпляру данного класса.

В классе можно объявить несколько модификаторов доступа. Например, добавим модификатор доступа private:
[cc lang=»delphi»]TTeacher = class
private
BaseId: integer; // Предположим, что это какой-либо идентификатор в базе данных, где хранятся данные об этом преподавателе.

procedure SaveToBase; // А это внутренний метод, который вероятно предназначен для записи обновленных данных в БД.
public
FullName: string;

constructor Create(NewFullName: string);
destructor Destroy;
end;[/cc]
Как вы видите, я описал одно поле и один метод, которые явно должны быть скрыты от внешнего использования, которые наверняка будут использоваться только внутри реализации самого класса. Именно поэтому мы будем использовать модификатор доступа private.

Private позволяет полностью ограничить доступ к ниже перечисленным полям и методам. При попытке к ним обратиться из внешнего кода они будут невидимы, попытки к ним обратиться будут запрещаться ошибкой компиляции.
[warning]Существует единственное ограничение для private — все поля и методы, находящиеся в этой группе доступа, будут в любом случае видимы внутри текущего юнита, в котором описан и реализован класс. Ограничение НЕ работает в юните, в котором описан и реализован класс, оно распространяется лишь на другие юниты.[/warning]
[tip]Одной из задач ООП является организация командной работы над проектом. Если какое-то поле или какой-то метод был вынесен в приватную группу доступа класса, то значит разработчик этого класса не рекомендует обращаться к этим полям и методам из внешнего кода, он просто ограничивает к ним доступ. В публичную группу доступа рекомендуется выносить только те поля и методы, которые предназначены для обращения к ним извне, для работы с классом из внешнего кода.[/tip]
Иногда возникает потребность в том, чтобы ограничить использование какого-либо метода или поля и во внешнем коде текущего юнита (в котором описан и реализован данный класс) тоже. Для этого существует группа доступа strict private.

Strict private — группа доступа, которая появилась в Delphi относительно недавно. Она позволяет, как уже было сказано, ограничить доступ к определенным полям и методам и в юните, в котором реализован и описан данный класс, в отличие от группы доступа private. Т.е. эта группа доступа действительно запрещает использование во всем внешнем коде, в том числе и в данном юните. Таким образом, ранее приведенный пример описания класса может выглядеть так:
[cc lang=»delphi»]TTeacher = class
strict private
BaseId: integer; // Предположим, что это какой-либо идентификатор в базе данных, где хранятся данные об этом преподавателе.

procedure SaveToBase; // А это внутренний метод, который вероятно предназначен для записи обновленных данных в БД.
public
FullName: string;

constructor Create(NewFullName: string);
destructor Destroy;
end;[/cc]
Итак, в этом уроке мы разобрали три группы доступа: private, strict private и public. И, конечно же, рассмотрели различия между ними. В следующем уроке мы рассмотрим принципы наследования классов — это тоже одна из наиболее важных парадигм. И при ее рассмотрении у нас появится еще одна группа доступа protected, но это уже совсем другая история…

Иллюстрированный самоучитель по Delphi 7 для начинающих

Директивы protected и private

Помимо объявления элементов класса (полей, методов, свойств) описание класса, как правило, содержит директивы protected (защищенный) и private (закрытый), которые устанавливают степень видимости элементов класса в программе.

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

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

Ниже приведено описание класса TPerson, в которое включены директивы управления доступом.

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

Блог GunSmoker-а (переводы)

. when altering one’s mind becomes as easy as programming a computer, what does it mean to be human.

среда, 7 июля 2010 г.

Хак №5: Доступ к private-полям

Это перевод Hack #5: Access to private fields. Автор: Hallvard Vassbotn.

Как вам говорила ваша мама, вам нужно защищать ваши личные данные и не трогать личные данные других людей. Это же применимо и в программировании. Инкапсуляция и скрытие информации — это два главных столпа в ООП, так что нам лучше бы не вмешиваться в это, точно? Точно. Но однажды при полной луне у меня возникла неодолимая жажда достучаться до private-полей другого класса (объявленного в другом модуле).

Когда возможен, ранее упомянутый хак является предпочтительным вариантом перед техникой, описанной в этой статье. Однако, иногда этот хак не практичен или невозможен. Использование RTTI — это относительно медленно (хотя вы можете применять кэширование), а private-поля могут быть и вовсе не раскрываться через свойства. Кроме того, если вам нужен доступ сразу ко всем private-полям, то решение, описываемое тут, также может быть более предпочтительным.

Как я упоминал ранее, концепция Delphi private данных (по сравнению со strict private в D2006 и выше) всё ещё позволяет другому коду в том же самом модуле обращаться с полным доступом к данным класса, но при этом исключает доступ из других модулей. Иными словами, все классы и подпрограммы в одном модуле непременно являются «друзьями» друг друга (в смысле C++).

Замечали ли вы как взаимодействуют некоторые VCL классы друг с другом? Например, абстрактный базовый класс для системы персистентности компонент (TFiler) определяет несколько private-полей. Но в действительности, с этими полями работают другие классы, объявленные в том же модуле: TReader и TWriter (оба, впрочем, наследники TFiler). Оба эти класса объявлены в этом же модуле и грубо используют private-поля, определённые в TFiler (к примеру, самое-важное-поле FStream).

И если вы захотите написать свою собственную систему персистентности уровня приложения (скажем, со способностью писать в поток и авто-создавать при загрузке не только наследников TComponent), которая будет, как и стандартная, участвовать в системе TPersistent.DefineProperties, то вам нужно расширить классы TReader и TWriter. Вам может показаться, что эти классы были спроектированы для расширения — ведь они объявляют новые виртуальные методы. Но ваши собственные классы TMyReader и TMyWriter не имеют доступа ни к private-полям TFiler ни к private-полям TReader и TWriter. Это может(*) серьёзно ограничить ваши возможности по расширению.

Окей, хватит уже рассуждений — перейдём к главному блюду. Чтобы получить доступ к private-полям класса TFiler, объявите shadow-класс (иногда называемый dummy-класс), который в точности соответствует раскладке полей в TFiler из Classes.pas:
Теперь, если у вас есть экземпляр TFiler, вы легко можете привести его тип к TFilerHack и получить доступ к полям:
Заметьте, что я использовал директиву видимости private в объявлении поля в классе TFilerHack — это всё равно даст вам доступ к полю для кода в том же модуле. Обычно, хак-классы подобного толка должны объявляться в секции implementation модуля.

Конечно же, этот хак чрезвычайно чувствителен к изменениям в исходном классе. Сравните это с другим решением: вычислением «волшебного смещения» поля от начала класса. Это решение имеет то преимущество, что всю работу по вычислению смещения вы перекладываете на компилятор. Кроме того, при этом получается, что вы защищены от изменений в предках хакаемого класса (в случае TFiler это только TObject). Если вам где-то придётся использовать этот хак, то убедитесь, что вы использовали <$IFDEF>или <$IF>для защиты кода от изменений в компиляторе, RTL или сторонней библиотеке.

(*) Несколько лет назад (сидя на D5), я вообще-то реализовал свою собственную систему персистентности, написанием своих собственных классов TReader и TWriter и используя хаки, похожие на описываемые в этой статье. С тех пор TFiler, TReader и TWriter были улучшены и в частности улучшены для расширения — к примеру, предоставляя protected-доступ к некоторым бывшим private-полям (все дружно сказали «спасибо» Borland CodeGear!). Так что вполне возможно, что эта система может быть переписана без хаков на D7, но я это не проверял. Я просто буду использовать TFiler как пример для иллюстрации принципа.

Private — Директива Delphi

Помимо объявления элементов класса (полей, методов, свойств) описание класса, как правило, содержит директивы protected (защищенный) и private (закрытый), которые устанавливают степень видимости элементов класса в программе.

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

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

Ниже приведено описание класса TPerson, в которое включены директивы управления доступом.

TPerson = class private

FName: TName; // значение свойства Name

FAddress: TAddress; // значение свойства Address

Function GetName: TName;

Function GetAddress: TAddress;

Property Name: TName

Property Address: TAddress

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

Private — Директива Delphi

Use the static storage class specifier with a local variable to preserve the last value between successive calls to that function. A static variable acts like a local variable but has the lifetime of an external variable.

In a class, data and member functions can be declared static. Only one copy of the static data exists for all objects of the class.

A static member function of a global class has external linkage. A member of a local class has no linkage. A static member function is associated only with the class in which it is declared. Therefore, such member functions cannot be virtual.

Static member functions can only call other static member functions and only have access to static data. Such member functions do not have a this pointer.

По нажатию F1 в среде Delphi2006 выдается сообщение No topic-basedn help system installed, хотя
C:\Program Files\Common Filse\Microsoft Shared\Help\dexplore.exe установлен и работает, но хотелось бы чтобы поиск осуществлялся в самой среде Delphi, как это сделать. У меня Delphi лицензионный на 5-ти дисках мож от туда что-нужно взять.

Добавлено 30.07.07, 09:46
Что значит директива strict

Все должно было поставиться автоматом. Попробуй поверх переустановить в режиме восстановления.

Strict Visibility Specifiers
In addition to private and protected visibility specifiers, the Delphi compiler supports additional visibility settings with greater access constraints. These settings are strict private and strict protected visibility. These settings strictly comply with the .NET Common Language Specification (CLS), and they can also be used in Win32 applications.

Class members with strict private visibility are accessible only within the class in which they are declared. They are not visible to procedures or functions declared within the same unit. Class members with strict protected visibility are visible within the class in which they are declared, and within any descendant class, regardless of where it is declared. Furthermore, when instance members (those declared without the class or class var keywords) are declared strict private or strict protected, they are inaccessible outside of the instance of a class in which they appear. An instance of a class cannot access strict protected or strict protected instance members in other instances of the same class.

Delphi’s traditional private visibility specifier maps to the CLR’s assembly visibility. Delphi’s protected visibility specifier maps to the CLR’s assembly or family visibility.

Note: The word strict is treated as a directive within the context of a class declaration. Within a class declaration you cannot declare a member named ‘strict’, but it is acceptable for use outside of a class declaration.

Мысли Delphi — разработчика

Работать нужно не 12 часов, а головой! © Стив Джобс

26.09.2013

Приватные (private) секции видимости класса

A private member is invisible outside of the unit or program where its class is declared. In other words, a private method cannot be called from another module, and a private field or property cannot be read or written to from another module. By placing related class declarations in the same module, you can give the classes access to one another’s private members without making those members more widely accessible. For a member to be visible only inside its class, it needs to be declared strict private.

Директива Private начинает раздел данных (полей) и подпрограмм (методы) класса, которые являются частными (внутренними) для этого класса. Это — жизненно важная часть Объектно-ориентированной концепции, в которой класс рассматривается как черный ящик — то, что используется внутри не уместно для внешнего использования. Указанные в частном (Private) разделе данные и подпрограммы используются другими подпрограммами только данного класса.
Если частные данные нуждаются во внешнем доступе, то свойство public (или published) предоставят данный доступ.
Частные (Private) данные и подпрограммы не доступны даже потомкам класса, чтобы обеспечить этот доступ вы должны использовать Protected. Защищенные (Protected) данные и методы внешне невидимы, но доступны для всех классов в иерархии.

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

Delphi 2007 — новинки языка по сравнению с Delphi 7 (исходники)

1. Директива inline — процедуры могут теперь быть маркированы как inline. В этом случае компилятор просто подставляет тело такой процедуры в точку вызова.

Илон Маск рекомендует:  Библиотека Bourbon

2. Перегрузка операторов (не путать с методами). Поясню — теперь вы можете написать свой оператор наподобие + или -.

Зато теперь вы можете «улучшить» код какого нибудь компонента не переписывая его ;)

4. strict private — наконец то private стал приватным по настоящему. Когда вы описываете методы как приватные они все равно видны по крайней мере в рамках одного unit. То есть это отношение «friend» в терминах C++. Когда вы делаете метод strict private — это означает действительно приватный метод или свойство для класса и не не видим никому, даже в рамках unit.

5. strict protected — по образу и подобию п.4 — только такие методы будут видимы самому классу владельцу и его наследникам. И никакого friendship ;)

6. Записи с методами. Record теперь может иметь не только свойства но и методы (конструкторы в том числе), классовые свойства, методы, свойства а также вложенные типы.

7. Астрактные классы — Теперь не только методы но и сами классы могут быть абстрактными.

8. Sealed class — так называемые «запечатанные классы» — то есть классы от которых нельзя породить наследника.

9. Классовые константы

10. Типы внутри класса — класс может теперь содержать объявления типов которые используются только втрутри класса.

11. Классовые переменные и константы — теперь можно вот так:

12. Вложенные классы — сделаны для того чтобы концептуально родственные типы были близко и для того чтобы предотвратить возможные конфликты имен.

13. final methods — виртуальные методы которые вы перекрываете могут быть помечены как final, что сделает невозможным их дальнейшее перекрытие.

14. sealed classes — теперь классы могут быть sealed и в противоположность class abstract не могут имеить наследников.

15. Статические методы классов. — то что мы все так хотели. Теперь методы могут быть вызваны без создания экземпляра класса. В такие методы не передается указатель Self и разумеется такие методы не могут использовать даные экземпляра класса.

16. for-element-in-collection — по заявкам VB-шников. Теперь ваш любимый for each работает и в дельфи

Delphi «частный» пункт (директива) не работает

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

Пожалуйста, помогите мне, может быть, я пропустил что-то о том, как инкапсуляция должна работать.

Этот код не должен работать. Я полагаю. Но это работает.

Спасибо. (Delphi-7, Win7 x64).

private является для unit .

С более новой версией Delphi, вы можете использовать , strict private чтобы получить ожидаемое поведение.

Частные, Protected и открытые члены

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

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

Общественный элемент виден везде , где можно ссылаться его класс.

Строгие Видимость спецификаторы

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

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

Традиционная Деая частная видимость Спецификатор карты для видимости сборок СЬКА. Delphi , защищенная видимость Спецификатор карты для сборки или семьи видимости в СЬКЕ.

Примечание : Слово строго рассматриваются как директива в контексте описания класса. В объявлении класса вы не можете объявить элемент с именем «строгими», но это приемлемо для использования за пределами объявления класса.

Ваша версия Delphi, Delphi 7 не поддерживает strict описатели.

Private — Директива Delphi

Классы очень удобно собирать в модули. При этом их описание помещается в секцию interface, а код методов — в секцию implementation. Создавая модули классов, нужно придерживаться следующих правил:

  • все классы, предназначенные для использования за пределами модуля, следует определять в секции interface;
  • описание классов, предназначенных для употребления внутри модуля, следует располагать в секции implementation;
  • если модуль B использует модуль A, то в модуле B можно определять классы, порожденные от классов модуля A.

Соберем рассмотренные ранее классы TTextReader, TDelimitedReader и TFixedReader в отдельный модуль ReadersUnit:

Как можно заметить, в описании классов присутствуют новые ключевые слова private, protected и public. С их помощью регулируется видимость частей класса для других модулей и основной программы. Назначение каждого ключевого слова поясняется ниже.

Разграничение доступа к атрибутам объектов

Программист может разграничить доступ к атрибутам своих объектов для других программистов (и себя самого) с помощью специальных ключевых слов: private, protected, public, published (последнее не используется в модуле ReadersUnit).

  • Private. Все, что объявлено в секции private недоступно за пределами модуля. Секция private позволяет скрыть те поля и методы, которые относятся к так называемым особеностям реализации. Например, в этой секции класса TTextReader объявлены поля FFile, FActive и FItems, а также методы PutItem, SetActive, GetItemCount и GetEndOfFile.
  • Public. Поля, методы и свойства, объявленные в секции public не имеют никаких ограничений на использование, т.е. всегда видны за пределами модуля. Все, что помещается в секцию public, служит для манипуляций с объектами и составляет программный интерфейс класса. Например, в классе TTextReader в эту секцию помещены конструктор Create, метод NextLine, свойства Active, Items, ItemCount.
  • Protected. Поля, методы и свойства, объявленные в секции protected, видны за пределами модуля только потомкам данного класса; остальным частям программы они не видны. Так же как и private, директива protected позволяет скрыть особенности реализации класса, но в отличие от нее разрешает другим программистам порождать новые классы и обращаться к полям, методам и свойствам, которые составляют так называемый интерфейс разработчика. В эту секцию обычно помещаются виртуальные методы. Примером такого метода является ParseLine.
  • Published. Устанавливает правила видимости те же, что и директива public. Особенность состоит в том, что для элементов, помещенных в секцию published, компилятор генерирует информацию о типах этих элементов. Эта информация доступна во время выполнения программы, что позволяет превращать объекты в компоненты визуальной среды разработки. Секцию published разрешено использовать только тогда, когда для самого класса или его предка включена директива компилятора $TYPEINFO.

Перечисленные секции могут чередоваться в объявлении класса в произвольном порядке, однако в пределах секции сначала следует описание полей, а потом методов и свойств. Если в определении класса нет ключевых слов private, protected, public и published, то для обычных классов всем полям, методам и свойствам приписывается атрибут видимости public, а для тех классов, которые порождены от классов библиотеки VCL, — атрибут видимости published.

Внутри модуля никакие ограничения на доступ к атрибутам классов, реализованных в этом же модуле, не действуют. Кстати, это отличается от соглашений, принятых в некоторых других языках программирования, в частности в языке C++.

Указатели на методы объектов

В языке Delphi существуют процедурные типы данных для методов объектов. Внешне объявление процедурного типа для метода отличается от обычного словосочетанием of object, записанным после прототипа процедуры или функции:

Переменная такого типа называется указателем на метод (method pointer). Она занимает в памяти 8 байт и хранит одновременно ссылку на объект и адрес его метода.

Методы объектов, объявленные по приведенному выше шаблону, становятся совместимы по типу со свойством OnReadLine.

Если установить значение свойства OnReadLine:

и переписать метод NextLine,

то объект Form1 через метод HandleLine получит уведомление об очередной считанной строке. Обратите внимание, что вызов метода через указатель происходит лишь в том случае, если указатель не равен nil. Эта проверка выполняется с помощью стандартной функции Assigned, которая возвращает True, если ее аргумент является связанным указателем.

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

Метаклассы

Ссылки на классы

Язык Delphi позволяет рассматривать классы объектов как своего рода объекты, которыми можно манипулировать в программе. Такая возможность рождает новое понятие — класс класса; его принято обозначать термином метакласс.

Для поддержки метаклассов введен специальный тип данных — ссылка на класс (class reference). Он описывается с помощью словосочетания class of, например:

Переменная типа TTextReaderClass объявляется в программе обычным образом:

Значениями переменной ClassRef могут быть класс TTextReader и все порожденные от него классы. Допустимы следующие операторы:

По аналогии с тем, как для всех классов существует общий предок TObject, у ссылок на классы существует базовый тип TClass, определенный, как:

Переменная типа TClass может ссылаться на любой класс.

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

Физический смысл и взаимосвязь таких понятий, как переменная-объект, экземпляр объекта в памяти, переменная-класс и экземпляр класса в памяти поясняет рисунок 4.

Рисунок 4. Переменная-объект, экземпляр объекта в памяти, переменная-класс и экземпляр класса в памяти

Методы классов

Метаклассы привели к возникновению нового типа методов — методов класса. Метод класса оперирует не экземпляром объекта, а непосредственно классом. Он объявляется как обычный метод, но перед словом procedure или function записывается зарезервированное слово class, например:

Передаваемый в метод класса неявный параметр Self содержит не ссылку на объект, а ссылку на класс, поэтому в теле метода нельзя обращаться к полям, методам и свойствам объекта. Зато можно вызывать другие методы класса, например:

Метод ClassName объявлен в классе TObject и возвращает имя класса, к которому применяется. Очевидно, что надуманный метод GetClassName просто дублирует эту функциональность для класса TTextReader и всех его наследников.

Методы класса применимы и к классам, и к объектам. В обоих случаях в параметре Self передается ссылка на класс объекта. Пример:

Методы классов могут быть виртуальными. Например, в классе TObject определен виртуальный метод класса NewInstance. Он служит для распределения памяти под объект и автоматически вызывается конструктором. Его можно перекрыть в своем классе, чтобы обеспечить нестандартный способ выделения памяти для экземпляров. Метод NewInstance должен перекрываться вместе с другим методом FreeInstance, который автоматически вызывается из деструктора и служит для освобождения памяти. Добавим, что размер памяти, требуемый для экземпляра, можно узнать вызовом предопределенного метода класса InstanceSize.

Виртуальные конструкторы

Особая прелесть ссылок на классы проявляется в сочетании с виртуальными конструкторами. Виртуальный конструктор объявляется с ключевым словом virtual. Вызов виртуального конструктора происходит по фактическому значению ссылки на класс, а не по ее формальному типу. Это позволяет создавать объекты, классы которых неизвестны на этапе компиляции. Механизм виртуальных конструкторов применяется в среде Delphi при восстановлении компонентов формы из файла. Восстановление компонента происходит следующим образом. Из файла считывается имя класса. По этому имени отыскивается ссылка на класс (метакласс). У метакласса вызывается виртуальный конструктор, который создает объект нужного класса.

На этом закончим изучение теории объектно-ориентированного программирования и в качестве практики рассмотрим несколько широко используемых инструментальных классов среды Delphi. Разберитесь с их назначением и работой. Это поможет глубже понять ООП и пригодится на будущее.

Классы общего назначения

Как показывает практика, в большинстве задач приходится использовать однотипные структуры данных: списки, массивы, множества и т.д. От задачи к задаче изменяются только их элементы, а методы работы сохраняются. Например, для любого списка нужны процедуры вставки и удаления элементов. В связи с этим возникает естественное желание решить задачу «в общем виде», т.е. создать универсальные средства для управления основными структурами данных. Эта идея не нова. Она давно пришла в голову разработчикам инструментальных пакетов, которые быстро наплодили множество вспомогательных библиотек. Эти библиотеки содержали классы объектов для работы со списками, коллекциями (динамические массивы с переменным количеством элементов), словарями (коллекции, индексированные строками) и другими «абстрактными» структурами. Для среды Delphi тоже разработаны аналогичные классы объектов. Их большая часть сосредоточена в модуле Classes. Наиболее нужными для вас являются списки строк (TStrings, TStringList) и потоки (TSream, THandleSream, TFileStream, TMemoryStream и TBlobStream). Рассмотрим кратко их назначение и применение.

Классы для представления списка строк

Для работы со списками строк служат классы TStrings и TStringList. Они используются в библиотеке VCL повсеместно и имеют гораздо большую универсальность, чем та, что можно почерпнуть из их названия. Классы TStrings и TStringList служат для представления не просто списка строк, а списка элементов, каждый из которых представляет собой пару строка-объект. Если со строками не ассоциированы объекты, получается обычный список строк.

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

Свойства класса TStrings описаны ниже.

  • Count: Integer — число элементов в списке.
  • Strings[Index: Integer]: string — обеспечивает доступ к массиву строк по индексу. Первая строка имеет индекс, равный 0. Свойство Strings является основным свойством объекта.
  • Objects[Index: Integer]: TObject — обеспечивает доступ к массиву объектов. Свойства Strings и Objects позволяют использовать объект TStrings как хранилище строк и ассоциированных с ними объектов произвольных классов.
  • Text: string — позволяет интерпретировать список строк, как одну большую строку, в которой элементы разделены символами #13#10 (возврат каретки и перевод строки).

Наследники класса TStrings иногда используются для хранения строк вида Имя=Значение, в частности, строк INI-файлов (см. гл. 6). Для удобной работы с такими строками в классе TStrings дополнительно имеются следующие свойства.

  • Names[Index: Integer]: string — обеспечивает доступ к той части строки, в которой содержится имя.
  • Values[const Name: string]: string — обеспечивает доступ к той части строки, в которой содержится значение. Указывая вместо Name ту часть строки, которая находится слева от знака равенства, вы получаете ту часть, что находится справа.

Управление элементами списка осуществляется с помощью следующих методов:

  • Add(const S: string): Integer — добавляет новую строку S в список и возвращает ее позицию. Новая строка добавляется в конец списка.
  • AddObject(const S: string; AObject: TObject): Integer — добавляет в список строку S и ассоциированный с ней объект AObject. Возвращает индекс пары строка-объект.
  • AddStrings(Strings: TStrings) — добавляет группу строк в существующий список.
  • Append(const S: string) — делает то же, что и Add, но не возвращает значения.
  • Clear — удаляет из списка все элементы.
  • Delete(Index: Integer) — удаляет строку и ассоциированный с ней объект. Метод Delete, также как метод Clear не разрушают объектов, т.е. не вызывают у них деструктор. Об этом вы должны позаботиться сами.
  • Equals(Strings: TStrings): Boolean — Возвращает True, если список строк в точности равен тому, что передан в параметре Strings.
  • Exchange(Index1, Index2: Integer) — меняет два элемента местами.
  • GetText: PChar — возвращает все строки списка в виде одной большой нуль-терминированной строки.
  • IndexOf(const S: string): Integer — возвращает позицию строки S в списке. Если заданная строка в списке отсутствует, функция возвращает значение -1.
  • IndexOfName(const Name: string): Integer — возвращает позицию строки, которая имеет вид Имя=Значение и содержит в себе Имя, равное Name.
  • IndexOfObject(AObject: TObject): Integer — возвращает позицию объекта AObject в массиве Objects. Если заданный объект в списке отсутствует, функция возвращает значение -1.
  • Insert(Index: Integer; const S: string) — вставляет в список строку S в позицию Index.
  • InsertObject(Index: Integer; const S: string; AObject: TObject) — вставляет в список строку S и ассоциированный с ней объект AObject в позицию Index.
  • LoadFromFile(const FileName: string) — загружает строки списка из текстового файла.
  • LoadFromStream(Stream: TStream) — загружает строки списка из потока данных (см. ниже).
  • Move(CurIndex, NewIndex: Integer) — изменяет позицию элемента (пары строка-объект) в списке.
  • SaveToFile(const FileName: string) — сохраняет строки списка в текстовом файле.
  • SaveToStream(Stream: TStream) — сохраняет строки списка в потоке данных.
  • SetText(Text: PChar) — загружает строки списка из одной большой нуль-терминированной строки.
Илон Маск рекомендует:  Что такое код openssl_private_encrypt

Класс TStringList добавляет к TStrings несколько дополнительных свойств и методов, а также два свойства-события для уведомления об изменениях в списке. Они описаны ниже.

Свойства:

  • Duplicates: TDuplicates — определяет, разрешено ли использовать дублированные строки в списке. Свойство может принимать следующие значения: dupIgnore (дубликаты игнорируются), dupAccept (дубликаты разрешены), dupError (дубликаты запрещены, попытка добавить в список дубликат вызывает ошибку).
  • Sorted: Boolean — если имеет значение True, то строки автоматически сортируются в алфавитном порядке.

Методы:

  • Find(const S: string; var Index: Integer): Boolean — выполняет поиск строки S в списке строк. Если строка найдена, Find помещает ее позицию в переменную, переданную в параметре Index, и возвращает True.
  • Sort — сортирует строки в алфавитном порядке.

События:

  • OnChange: TNotifyEvent — указывает на обработчик события, который выполнится при изменении содержимого списка. Событие OnChange генерируется после того, как были сделаны изменения.
  • OnChanging: TNotifyEvent — указывает на обработчик события, который выполнится при изменении содержимого списка. Событие OnChanging генерируется перед тем, как будут сделаны изменения.

Ниже приводится фрагмент программы, демонстрирующий создание списка строк и манипулирование его элементами:

Классы для представления потока данных

В среде Delphi существует иерархия классов для хранения и последовательного ввода-вывода данных. Классы этой иерархии называются потоками. Потоки лучше всего представлять как файлы. Классы потоков обеспечивают различное физическое представление данных: файл на диске, раздел оперативной памяти, поле в таблице базы данных (таблица 1).

Таблица 1. Классы потоков

Класс

Описание

TStream Абстрактный поток, от которого наследуются все остальные. Свойства и методы класса TStream образуют базовый интерфейс потоковых объектов.
THandleStream Поток, который хранит свои данные в файле. Для чтения-записи файла используется дескриптор (handle), поэтому поток называется дескрипторным. Дескриптор — это номер открытого файла в операционной системе. Его возвращают низкоуровневые функции создания и открытия файла.
TFileStream Поток, который хранит свои данные в файле. Отличается от ThandleStream тем, что сам открывает (создает) файл по имени, переданному в конструктор.
TMemoryStream Поток, который хранит свои данные в оперативной памяти. Моделирует работу с файлом. Используется для хранения промежуточных результатов, когда файловый поток не подходит из-за низкой скорости передачи данных.
TResourceStream Поток, обеспечивающий доступ к ресурсам в Windows-приложении.
TBlobStream Обеспечивает последовательный доступ к большим полям таблиц в базах данных.

Потоки широко применяются в библиотеке VCL и наверняка вам понадобятся. Поэтому ниже кратко перечислены их основные общие свойства и методы.

Общие свойства:

  • Position: Longint — текущая позиция чтения-записи.
  • Size: Longint — текущий размер потока в байтах.

Общие методы:

  • CopyFrom(Source: TStream; Count: Longint): Longint — копирует Count байт из потока Source в свой поток.
  • Read(var Buffer; Count: Longint): Longint — читает Count байт из потока в буфер Buffer, продвигает текущую позицию на Count байт вперед и возвращает число прочитанных байт. Если значение функции меньше значения Count, то в результате чтения был достигнут конец потока.
  • ReadBuffer(var Buffer; Count: Longint) — читает из потока Count байт в буфер Buffer и продвигает текущую позицию на Count байт вперед. Если выполняется попытка чтения за концом потока, то генерируется ошибка.
  • Seek(Offset: Longint; Origin: Word): Longint — продвигает текущую позицию в потоке на Offset байт относительно позиции, заданной параметром Origin. Параметр Origin может иметь одно из следующих значений: 0 — смещение задается относительно начала потока; 1 — смещение задается относительно текущей позиции в потоке; 2 — смещение задается относительно конца потока.
  • Write(const Buffer; Count: Longint): Longint — записывает в поток Count байт из буфера Buffer, продвигает текущую позицию на Count байт вперед и возвращает реально записанное количество байт. Если значение функции отличается от значения Count, то при записи была ошибка.
  • WriteBuffer(const Buffer; Count: Longint) — записывает в поток Count байт из буфера Buffer и продвигает текущую позицию на Count байт вперед. Если по какой-либо причине невозможно записать все байты буфера, то генерируется ошибка.


Ниже приводится фрагмент программы, демонстрирующий создание файлового потока и запись в него строки:

Итоги

Теперь для вас нет секретов в мире ООП. Вы на достаточно серьезном уровне познакомились с объектами и их свойствами; узнали, как объекты создаются, используются и уничтожаются. Если не все удалось запомнить сразу — не беда. Возвращайтесь к материалам главы по мере решения стоящих перед вами задач, и работа с объектами станет простой, естественной и даже приятной. Когда вы достигните понимания того, как работает один объект, то автоматически поймете, как работают все остальные. Теперь мы рассмотрим то, с чем вы встретитесь очень скоро — ошибки программирования.

Private — Директива Delphi

Алексей Вуколов, Елена Филиппова, Игорь Шевченко, «Королевство Delphi»

Содержание

Первая страница

После загрузки среды перед нами возникает приветственная страница «Welcome Page». Это новый аналог того самого окошка новостей, которое выглядело довольно неказисто, если ваш компьютер не был подключен к интернету во время работы. Однако не стоит так же сбрасывать со счетов и новый вариант. Кроме ленты новостей (RSS), «Welcome Page» содержит немало полезных ссылок. Во-первых, в самом верху страницы перечислен список проектов, которые вы уже открывали некоторое время назад, с указанием даты последней модификации. Каждая ссылка, естественно, открывает выбранный проект.

В левой части страницы подобраны ссылки на справочную информацию, документацию, которая устанавливается на ваш компьютер при инсталяции Delphi2005. Далее идут ссылки в интернет, на страницы компаний-разработчиков, чьи продукты встроены в среду. Например, на страницу Rave Reports, IntraWeb и так далее. И, наконец, ссылки на новостные группы в интернете, BDN и другие страницы Borland-ресурсов. То есть, «Welcome Page», действительно содержит полезную информацию. Может быть, не часто придется ею пользоваться, но и забывать о ней не стоит, может пригодиться.

Среда предоставляет возможнсть работать как в классическом стиле предыдущих версий Delphi (с отдельными окнами для дизайнера форм, инспектора объектов и т.д.), так и в стиле, максимально приближенном к MS Visual Studio, когда все окна пристыковываются к центральному, в котором можно заниматься дизайном формы или редактированием кода.

Для того, чтобы привести окна редактирования и палитры компонентов к привычному виду, поэкспериментируйте с настройками Tools | Environment Options | Delphi Options | VCL Designer | Embedded designer и Tools | Environment Options | Tool Pallete.

В Delphi2005 изменилась справочная система. Изменился не только внешний вид, но внутренняя структура предлагаемой информации.

На мой взгляд, пользоваться справкой стало намного удобнее.

Появилась возможность настраивать цвета для Object Inspector, смотрите .

Редактор кода

С редактором кода стало работать намного удобнее.

Комментирование блока текста

Начнем с одной приятной мелочи. Не знаю, как кому, но мне ее иногда очень не хватало в Delphi. Я имею в виду возможность быстро закомментировать или раскомментировать блок текста в редакторе.

В новой IDE это делается легким движением руки. Выделяем текст, нажимаем клавиши [Ctrl+/] и весь выделенный код оказался закомментирован. Обратная операция делается точно так же. На всякий случай напомню, почему это лучше, чем обычные скобки <> в начале и конце куска кода. В случае использования в начале каждой строки двойного слеша нет никакой нужды заботиться о вложенных комментариях, которые могут уже быть в выделенном тексте. Этот способ «устранения» части кода бывает удобен при отладке.

Очень удобна новая возможность редактора показывать соответствующие пары скобок (см. рисунок).

Сворачивание части кода

Как и в Delphi8, в редакторе Delphi2005 реализовано частичное скрытие (сворачивание кода). Это позволяет работать с большими текстами, не прокручивая многостраничный экран. Достаточно оставить развернутым сейчас только тот код, который используется. Для того чтобы свернуть или развернуть нужный блок, специально предусмотрены значки [-] и [+] в левой части редактора. Если нажать на значок [-], например, возле определения метода, код этого метода будет свернут, то есть, убран из видимости. Но, кроме этого, есть возможность применить эту операцию ко всему коду, а не только к текущему месту.

В меню по правой кнопке мыши есть два пункта Fold и UnFold. Это, соответственно, операции «свернуть» и «развернуть». Для каждой из них нужно указать место действия. Например, свернуть все методы в коде или все определения типов. Хочется заметить, что «свернутая» часть кода никуда не девается, а лишь уходит из видимой части редактора. Так что, если при компиляции или во время работы «Error Insight», ошибка окажется в свернутом коде, он прекрасным образом будет развернут автоматически в нужном месте. Так что никакой путаницы не возникнет.

Кроме этих возможностей, введены две директивы, которые по синтаксису аналогичны директивам компилятора, но оказывают влияние на поведение редактора, а не на генерируемый код. Это директивы $REGION и $ENDREGION. Они задают начало и конец сворачиваемого региона кода. Можно задать имя региона, в этом случае, когда регион свернут, вместо многоточия отображается имя региона (см. рис).

Help Insight

Если в привычном «Code Insight» показывался тип идентификатора (переменной, функции и т.д.) и модуль, в котором он определен, то «Help Insight» представляет собой всплывающее окно-подсказку, с кратким описанием этого идентификатора и дополнительными ссылками (см. рис). Достаточно подвести мышку к нужному идентификатору, чтобы получить такой «маленький help». Использовать «Help Insight» можно в комбинации с «Code Completion». Если в окне «Code Completion» выбрать определенное свойство или метод, то справа появится окно с подсказкой.

Эта возможность реализована не только для стандартных, но и для собственных классов и переменных. Использование «Help Insight» включено по умолчанию. Местонахождение в настройках: Tools->Options->Editor Options->Code Insight

Error Insight

В левой части экрана есть окно «Structure». Оно используется для показа визуальных компонент, лежащих на форме, переменных и констант, списка модулей, которые подключены и так далее. Но, кроме этого окно «Structure» может показывать список синтаксических ошибок, которые определяются до момента компиляции с помощью «Error Insight».

Например, самая обычная ошибка — неверно написан идентификатор или не подключен модуль, в котором он определен. Если раньше, до момента компиляции эти ошибки не отслеживались, то сейчас ошибочные имена (идентификаторов, методов и т.п.) мгновенно обращают на себя внимание, так как в редакторе кода они подчеркиваются красной волнистой линией, а в окне «Structure» появляется полный список таких ошибок (см. рис). Естественно, что, кликнув на ошибке в списке, мы сразу попадаем на нужное место в коде.

Sync Edit

При выделении части кода в редакторе, на левой полосе, вслед за выделяемыми строками, передвигается маленькая иконка (на рисунке она отмечена красным). Это включение режима «Sync Edit». Если нажать на эту иконку, то выделенный текст подкрасится (при цветовых настройках по умолчанию) голубым цветом и будет выделен первый в блоке идентификатор.

Суть режима «Sync Edit» в том, что он позволяет показать в выделенном тексте все повторяющиеся идентификаторы, их может оказаться несколько групп. Самая первая считается текущей.

Для текущей группы все дубли помечены рамочкой, для остальных групп просто подчеркнуты. Переход между группами повторяющихся идентификаторов осуществляется клавишей TAB. Если начать изменять текущий идентификатор, то вслед за ним будут синхронно изменены все его дубли в этом выделенном блоке. Это похоже на «Рефакторинг: переименование идентификатора».

В отличие от полноценного рефакторинга, в режиме «Sync Edit» не производится никакого синтаксического анализа, а просто ищется повторяющееся имя. Его можно применять, как «быстрый рефакторинг» или использовать для поиска всех мест, где используется искомый идентификатор.

Рекомендуется использовать этот режим для небольших блоков кода, например, для функций или методов. Для всех остальных случаев рекомендуется использовать полноценный рефакторинг.

Повторное нажатие на иконку на левой полосе редактора кода, выключает «Sync Edit» и возвращает обычный режим редактирования.

История изменений

По мере редактирования и сохранения кода в проекте, средой автоматически ведется история этих изменений. Для каждого модуля, включенного в проект, можно просмотреть историю изменений, сравнить разные версии файлов и, если необходимо, возвратиться к любому из промежуточных изменений кода проекта. Смотрите закладку History в редакторе кода и тему «History Manager» в документации.

После даже этой небольшой работы с новой IDE, возвращение к старым версиям в свои рабочие проекты кажется откатом назад.

Но, есть и неприятные моменты.

Русские буквы в комментариях к коду

Поначалу неприятно удивило открытие файлов кода с комментариями в заголовке, написанными русскими буквами в кодировке Win1251. Часть таких файлов открываются, как двоичные. После небольшого исследования оказалось, что портит все маленькая буква «я» в тексте комментариев в начале модуля. Если в новой среде написать такой комментарий в начале модуля, то он редактируется нормально. Но, если его закрыть, то вновь откроется он в двоичном виде. По-видимому, проблема связана с тем, что редактор кода по первой порции фиксированного объема определяет формат файла. Встречая в этой порции букву «я» (ее код $FF), редактор некорректно определяет формат файла. При переносе текста с буквой «я» в конец файла или в середину файла большого размера, его формат определяется корректно.

Сходная ситуация обсуждалась в Подводных камнях.

Проблема с открытием таких файлов решается или удалением слов из заголовка модуля, содержащих маленькую букву «я», или замена ее на букву «Я» в верхнем регистре. Кому что нравится.

Русские буквы в названиях каталогов проекта

Проекты VCL.NET и WinForms не запускаются из-под среды, если в полном имени каталога проекта есть русские буквы. Среда сообщает «Unable to create process».

К сожалению, ссылки в окне «Help Insight» не будут работать, если у вас в названии каталогов используются русские буквы.

Рефакторинг

Рефакторинг «переименование символа» — при позиционировании курсора на нужном идентификаторе и выборе пункта меню Refactoring | Rename Field, среда показывает все строки, где встречается выбранный идентификатор, и предлагает выбрать новое имя. Очень удобная возможность, как тут не вспомнить Мартина Фаулера:

«Важной частью пропагандируемого мною стиля программирования является разложение сложных процедур на небольшие методы. Если делать это неправильно, то придется изрядно помучиться, выясняя, что же делают эти маленькие методы. Избежать таких мучений помогает назначение методам хороших имен. Методам следует давать имена, раскрывающие их назначение. Хороший способ для этого — представить себе, каким должен быть комментарий к методу, и преобразовать этот комментарий в имя метода. Жизнь такова, что удачное имя может не сразу придти в голову. В подобной ситуации может возникнуть соблазн бросить это занятие — в конце концов, не в имени счастье. Это вас соблазняет бес, не слушайте его. Если вы видите, что у метода плохое имя, обязательно измените его. Помните, что ваш код в первую очередь предназначен человеку, а только потом — компьютеру. Человеку нужны хорошие имена. Вспомните, сколько времени вы потратили, пытаясь что-то сделать, и насколько проще было бы, окажись у пары методов более удачные имена. Создание хороших имен — это мастерство, требующее практики; совершенствование этого мастерства — ключ к превращению в действительно искусного программиста. То же справедливо и в отношении других элементов сигнатуры метода. Если переупорядочивание параметров проясняет суть — выполните его.»

Раньше для подобных действий использовался метод переименования идентификатора в месте, где он объявлен, и инкрементная компиляция до выяснения всех мест, в которых этот идентификатор использовался.

Рефакторинг «Выделение метода» оказался вторым из удобных нововведений, в выделенном методе автоматически объявляются необходимые параметры и локальные переменные. К сожалению, пока остается мечтой автоматический поиск аналогичного кода выделенного метода в других местах и замена его вызововом выделенного метода.

Илон Маск рекомендует:  Как восстановить пароль в Одноклассниках

Рефакторинг: процесс выделения метода

После выделения метода

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

Unit-тестирование

«Мой опыт показывает, что создав хорошие тесты, можно значительно увеличить скорость программирования»
(с) Мартин Фаулер.

Delphi 2005 располагает встроенными средствами для организации тестирования работы отдельных модулей программы, основанными на известных open-source проектах DUnit и NUnit (.NET). Среда позволяет создать проект-оболочку для тестов и шаблоны тестирующих модулей. Рассмотрим возможности Delphi 2005 на примере тестирования простого класса, осуществляющего перевод чисел из двоичной формы в символьную по заданному основанию системы счисления и, наоборот, из символьной в двоичную.

Создадим класс, методы которого будут выполнять перевод, а основание системы счисления будет являться свойством класса.

Реализация метода ToString будет содержать ошибки, которые мы будем обнаруживать тестированием. Первая реализация выглядит так:

Создадим проект-оболочку для тестов командой File|New|Other выбрав в категории Unit Tests элемент Test Project (см. рис. 1 и 1-1).

Показать скриншоты в отдельном окне: рисунок 1 и рисунок 1-1

После этого группа проектов принимает вид:

Добавим в эту оболочку первый тестирующий модуль командой File|New|Other выбрав в категории Unit Tests элемент Test Case.

Показать скриншоты в отдельном окне:

В результате этих действий в IDE открывается окно с кодом сгенерированного класса для тестирования методов выбранного класса.

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

В методе Setup пишем код для вызова корректного конструктора

Метод TestToString принимает вид:

И последний метод — TestToNumber

Компилируем и запускаем тестовый проект, его окно выглядит так.

После запуска тестов видно, что один из методов исходного класса работает некорректно, так как полученный результат не соответствует ожидаемому (Ожидается ’10’ получен ‘AB’)

Анализируя исходный код метода, видно, что при переводе очередного знака числа, условия then и else необходимо поменять местами:

Перекомпилировав проект после исправления, снова запускаем тесты.

Видно, что ошибка исправлена, но метод все работает не так, как ожидается (Ожидается ’10’, получено ’01’).

Дальнейший анализ кода метода показывает, что при переводе числа в строку старшие цифры записываются после младших, исправляем эту ошибку, часть кода метода ToString теперь выглядит так:

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

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

Для проверки перевода чисел в другой системе счисления можно создать еще один Test Case, например, тестирующий перевод из двоичного вида в символьный и обратно в двоичной системе счисления.

После компиляции и запуска тестового проекта, видно, что новые тесты добавились к старым, так что любые исправления исходного кода можно протестировать как всеми созданными тестами, так и выбрав конкретные тесты.

В заключение хочется добавить, что использовать unit-тесты можно было и раньше. Например, полтора года назад, одним из авторов обзора была разработана среда подобного рода для того, чтобы полностью осознать, что же такое unit-тесты. Среда включала в себя главную программу и эксперт для генерации тестирующих модулей. Разумеется, не с таким красивым и удобным интерфейсом, гораздо больше кода приходилось писать вручную, но главный итог такой разработки и использования — осознание необходимости тестирования, в особенности, использования unit-тестов как значительного подспорья для разработки программ.

Спасибо фирме Borland, что такие нужны и удобные средства уже встроены в их новый продукт — Delphi 2005.

Компилятор

Предопределенный символ для идентификации компилятора — VER170 (выяснено опытным путем, в Help информация отсутствует).

Многие из перечисленных ниже возможностей являются нововведениями только для компилятора Win32.

for..in..do

В язык Delphi добавлена конструкция for..in..do для перебора всех членов массива, строки, множества или коллекции.

  • for Element in ArrayExpr do Stmt;
  • for Element in StringExpr do Stmt;
  • for Element in SetExpr do Stmt;
  • for Element in CollectionExpr do Stmt;

То есть, в цикле перебираются все элементы некоего множества и для каждого выполняется тело цикла. Например, теперь ничего не стоит перевернуть строку наоборот (см. рис)

Полная и весьма понятная информация находится в справке, смотрите раздел «Declarations and Statements»

Наиболее интересным применением циклов такого вида является их использование с коллекциями для перебора элементов. Для того, чтобы класс можно было использовать с циклами for..in, класс должен реализовать предопределенный паттерн коллекции. А именно, класс должен удовлетворять следующим требованиям:

  • содержать public метод экземпляра с именем GetEnumerator, который должен возвращать экземпляр класса, ссылку на интерфейс или запись (record).
  • экземпляр класса, ссылка на интерфейс или запись, возвращенные методом GetEnumerator, должны содержать public метод экземпляра с именем MoveNext, возвращающий значение типа boolean.
  • экземпляр класса, ссылка на интерфейс или запись, возвращенные методом GetEnumerator должны содержать public свойство экземпляра с именем Current, тип которого должен соответствовать типу элементов контейнера.

Экземпляр, возвращенный методом GetEnumerator, автоматически разрушается после окончания цикла for..in.

Следующий пример показывает реализацию паттерна коллекции

Поддержка синтаксиса for. in уже встроена в ряд классов VCL, например, TList, TComponent, TCollection, и т.д. — в общей сложности около 15 классов. Так, например, перечисление имен компонентов формы может выглядеть следующим образом (хотя и непривычно):

Модификаторы области видимости

Для большей совместимости исходного кода с Delphi for .NET введены два новых модификатора области видимости членов класса.

strict private

Члены класса с видимостью strict private доступны только самому классу.

strict protected

Члены класса с видимостью strict protected доступны только самому классу и его непосредственным наследникам.

Отличие новых модификаторов от традиционных private и protected заключается в том, что члены с новыми модификаторами не доступны постороннему коду, находящемуся в том же модуле.

Class property

Раньше, хотя компилятор и позволял использовать методы класса в качестве аксессоров свойств, обращение к таким свойствам в форме TSomeClass.PropName было невозможно. Теперь, с введением свойств класса такое обращение разрешено. Однако, в отличие от Delphi for .NET, свойства класса могут работать только через методы, т.к. понятие полей класса для компилятора Delphi for Win32 отсутствует.

Вложенные типы данных и константы

Эта возможность также является новшеством только для компилятора Delphi for Win32. Теперь, как и в случае с Delphi for .NET, можно объявлять типы данных и константы внутри других классов.

Обращение ко вложенным типам и константам производится через имя типа, в который они вложены, например, TOuterClass.TInnerClass или TOuterClass.x. Для вложенных типов и констант действуют те же модификаторы видимости, что и для остальных членов классов.

Существует одна интересная особенность. Хотя компилятор для Win32 не поддерживает полей класса, их в какой-то мере можно заменить вложенными типизированными константами при условии, что включена опция компилятора $J (она же $WRITEABLECONST).

Ненаследуемые классы

Если по каким-то причинам разработчик хочет запретить создание наследников класса, это можно сделать используя модификатор sealed.

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

Например, компиляция кода

приведет к ошибке — E2352 Cannot override a final method.

XML Documentation

Для компилятора Delphi for .NET эта возможность существует с версии Delphi 8. Теперь эта возможность доступна и в компиляторе для Win32. Компилятор умеет различать в исходном тексте специальным образом оформленные комментарии и генерировать на их основе XML файлы. Формат комментариев во многом похож на XML. Каждый комментарий, который будет анализироваться на наличие тегов XML документации предшествовует документируемому объекту и должен начинаться с комбинации из трёх символов «/». Существует набор тегов, которые рекомендуется применять при оформлении комментариев. Он описан в справке .NET SDK. К сожалению для тех, кто не любит писать всякие теги руками, IDE никак не облегчает оформление таких комментариев.

Примитивный пример оформления документации:

Примерный вид XML документации, генерируемой компилятором:

Inline

В новой версии компилятора Delphi появилась возможность использования inline кода. Для этого наполнена новым смыслом директива inline. Теперь, если процедура или функция имеют директиву inline, это заставит компилятор попытаться вставить в место, где эта процедура используется, не вызов, а код тела процедуры. Само наличие директивы inline ещё не гарантирует того, что попытка будет удачной. Существуют определенные ограничения. Согласно справочной системе, эти ограничения таковы:

  • inline не работает для любых видов методов позднего связывания (virtual, dynamic, message)
  • inline не работает для процедур содержащих код на языке ассемблера,
  • inline не работает для конструкторов и деструкторов
  • inline не работает для главного блока программы и секций инициализации и финализации модулей
  • inline код может быть использован внутри пакетов, но inline не работает через границы пакетов
  • inline не работает в модулях, связанных кольцевой зависимостью. Это ограничение включает и неявные кольцевые ссылки между модулями. Например, если модуль A использует модуль B, модуль B использует C, а C, в свою очередь, использует A, то при компиляции модуля A не будет производиться inline-подстановка кода из модулей B и C.
  • inline-подстановка в модулях, входящих в кольцевые зависимости, может быть произведена, если подстановка производится из модуля, не входящего в кольцо зависимостей. Например, если в предыдущем примере модуль A использует также модуль D, то в модуле A возможна inline-подстановка кода из модуля D.
  • inline не работает, если процедура объявлена в секции interface модуля и обращается к символам, объявленным в секции implementation.
  • inline не работает для методов в классах, если они обращаются к членам классов, имеющим более низкую видимость, чем сам метод. Например, если public метод обращается к private методу, то для такого метода inline-подстановка осуществляться не будет.
  • если процедура, помеченная как inline использует процедуры или переменные из внешних модулей, то все эти модули должны быть перечислены в списке uses того модуля, где inline процедура будет использована, иначе inline-подстановка не производится.
  • inline-подстановка не осуществляется для процедур и функций, которые используются в выражениях проверки условия циклов while и repeat.

При использовании inline процедур следует помнить о том, что изменение кода такой процедуры приведет к перекомпиляции всех модулей, где она используется.

Также для контроля использования inline-подстановок введена директива компилятора <$INLINE>. Она может принимать следующие значения:

  • - Процедуры, с директивой inline будут помечены, как процедуры, для которых возможна inline-подстановка. При вызове таких процедур будет сделана попытка inline подстановки кода. Действует по умолчанию.
  • - Процедуры, с директивой inline будут помечены, как процедуры, для которых возможна inline-подстановка только в том случае, если код процедуры будет размером меньше 32 байт.
  • - Процедуры, не смотря на наличие директивы inline, никогда не будут помечены, как процедуры, для которых возможна inline-подстановка. При вызове процедур попытка inline подстановки кода не будет сделана.
Unsafe Code

Для компилятора Delphi for .NET добавлена возможность включения небезопасного кода в приложения .NET. Для этого введена локальная директива компилятора <$UNSAFECODE>, которая может принимать значения ON и OFF а также добавлено ключевое слово unsafe, которое применяется к процедурам и функциям. Приложения, использующие небезопасный код не проходит проверку при помощи утилиты PEVerify. Подробнее о небезопасном коде смотрите в документации .NET SDK.

Unicode-идентификаторы

Появилась возможность использовать в именах типов и переменных символы Unicode.

выглядит понятнее, чем

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

Пример компилирующегося и работающего кода:

Расширенный синтаксис объявления и инициализации массивов

Delphi для Win32

Теперь можно делать задание размеров массива и инициализацию одной строкой

Delphi for .NET

Новый расширенный синтаксис позволяет объявлять массивы в форме

Также возможна инициализация массивов при помощи стандартной процедуры new.

Отладка

Понравилось поведение системы при возникновении Exception — появляется окно с уведомлением об Exception и с возможностью поставить галочку "Игнорировать этот тип Exception", вместо того, чтобы открывать окно Tools | Debugger..

Изменилась работа с точками останова. Появилась очень удобная возможность, не удаляя точку останова, отключить ее, пометив как "disable". Это можно сделать в редакторе кода по правой кнопке на точке останова, и прямо в списке "Breakpoint list". В этом списке можно включать/выключать все точки или определенные группы (меню по правой кнопке). Так же, теперь прямо в окне "Breakpoint list" можно изменять значение Condition и принадлежность к определенной группе для каждой точки.

Встроенный Data Explorer

В IDE интегрирован Data Explorer, который содержит как средства просмотра базы данных, так и ряд инструментов для редактирования. Окно Data Explorer можно найти на одной из закладок окна Project Manager справа от редактора кода (при умолчанных настройках среды) или в меню View | Data Explorer

Выбираете провайдера для вашей БД, настраиваете коннекцию к базе и получаете список ее объектов:

Таблицы

Для таблиц определены следующие операции:

Просмотр данных

Это операция по умолчанию — двойной клик по имени таблицы в списке. Открывается отдельное окно с содержимым таблицы. Возможно редактировать все поля, даже identity и computed column. Диагностика производится в момент сохранения изменений (правая кнопка мыши | Update/Rollback), так что испортить таблицу затруднительно.

Изменение структуры

Визуальный аналог команды "Alter table".

В этом окне по правой кнопке мыши доступны команды Save changes/Show DDL/ Exeсute DDL

DDL (Data definition language) — текст SQL-скрипта, который отражает сделанные визуально изменения в структуре таблицы.

Удаление таблицы

Выполнение команды "Drop table"

Копирование таблицы

Копирование существующей таблицы в новую. Происходит, как создание новой таблицы с такой же структурой (имя новой таблицы запрашивается при выполнении paste) и заполнении ее данным из копируемой таблицы.

Хранимые процедуры

Доступные операции Refresh/View Parameters. Окно просмотра параметров открывается при двойном клике на имени процедуры. В этом окне можно указать значения всех входных параметров и, выполнив процедуру, получить заполненные значениями выходные параметры (см. рис). Для выполнения процедуры можно воспользоваться иконкой в верхнем левом углу окна или по правой кнопке мыши (команда Execute).

Если хранимая процедура в качестве результата возвращает еще и (или только) набор данных, необходимо поставить галочку "Stored procedure has one or more cursors" и выполнить процедуру снова.

Просмотр скриншотов в отдельном окне:

Безусловно, новые возможности для тестирования работы хранимых процедур очень удобны и позволят упростить жизнь разработчика баз данных.

В качестве недостатка можно отметить отсутствие возможности прервать выполнение хранимой процедуры, если время выполнения оказывается довольно продолжительным.

SQL Window

Это привычное окно для выполнения SQL-запросов. Так как тестирование проходило только для MS SQL Server, то возможно, некоторые странности связаны с конкретным драйвером.

Сами SQL-запросы любой сложности (UNION, вложенные подзапросы и т.п.) выполняются без проблем. Странности начались после попытки исполнить в этом окне процедуру ("execute имя_процедуры"), которая в качестве результата возвращает набор данных. В качестве результата было получено сообщение "-1 row(s) affected". И этот результат был одинаков для всех процедур одного сервера. Тест на другом сервере дал иной результат, возможно этот эффект зависит от настроек на сервере (или от настроек конкретной базы), но такого иследования не проводилось. Итак, на другом сервере после выполнения процедуры было получено окошко с сообщением, например, таким: "192 row(s) affected", что само по себе верно, но никакого результата, то есть набора данных, все равно не было выведено. Если в тексте процедуры был оператор "Insert Into имя_таблицы exec имя_процедуры", то в качестве nколичества обработанных строк в результирующем сообщении выдавалось количество строк этого insert'а, а вовсе не nпоследнего select'а процедуры.

Можно предположить, что проблема кроется в ADO.NET, на котором реализован Data Explorer.

И, все же, несмотря на это, Data Explorer добавляет в среду разработки функционал, который реально может облегчить жизнь разработчику клиентских приложений для баз данных.

Данный обзор составлен по результатам первого знакомства с новой средой разработки. Изучить все нововведения в Delphi2005 за короткий срок невозможно, но такой задачи мы и не ставили перед собой. Разделив работу на параллельные части, мы постарались охватить как можно больше интересных, с нашей точки зрения, нововведений и "вкусностей" нашей любимой среды разработки.

Спасибо компании Borland за возможность ознакомиться с новой версией, которая несомненно, позволит вывести разработку приложений на качественно новый этап.

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL