Введение в программирование

Области применения языков программирования

В настоящее время языки программирования применяются в самых различных областях человеческой деятельности, таких как:
  • научные вычисления (языки C++, FORTRAN, Java);
  • системное программирование (языки C++, Java);
  • обработка информации (языки C++, COBOL, Java);
  • искусственный интеллект (LISP, Prolog);
  • издательская деятельность (Postscript, TeX);
  • удаленная обработка информации (Perl, PHP, Java, C++);
  • описание документов (HTML, XML).

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


  • Парадигмы программирования

    Синтаксис языка описывает систему правил написания различных языковых конструкций, а семантика языка программирования определяет смысл этих конструкций. Синтаксис языка программирования может быть описан с помощью НБФ-нотаций.
    Семантика языка взаимосвязана с используемой вычислительной моделью. В настоящее время языки программирования в зависимости от применяемой вычислительной модели делятся на четыре основные группы:
  • Процедурные языки, которые представляют собой последовательность выполняемых операторов. Если рассматривать состояние ПК как состояние ячеек памяти, то процедурный язык – это последовательность операторов, изменяющих значение одной или нескольких ячеек. К процедурным языкам относятся FORTRAN, C, Ada, Pascal, Smalltalk и некоторые другие. Процедурные языки иногда также называются императивными языками. Код программы на процедурном языке может быть записан следующим образом: оperator1; operator2; operator3;
  • Аппликативные языки, в основу которых положен функциональный подход. Язык рассматривается с точки зрения нахождения функции, необходимой для перевода памяти ПК из одного состояния в другое. Программа представляет собой набор функций, применяемых к начальным данным, позволяющий получить требуемый результат. К аппликативным языкам относится язык LISP. Код программы на аппликативном языке может быть записан следующим образом:
    function1(function2( function3(beginning_date)));
  • Языки системы правил, называемые также языками логического программирования, основываются на определении набора правил, при выполнении которых возможно выполнение определенных действий. Правила могут задаваться в виде утверждений и в виде таблиц решений. К языкам логического программирования относится язык Prolog.
    Код программы на языке системы правил может быть записан следующим образом:
    if condition1 then operator1; if condition2 then operator2; if condition3 then operator3;
  • Объектно-ориентированные языки, основанные на построении объектов как набора данных и операций над ними. Объектно-ориентированные языки объединяют и расширяют возможности, присущие процедурным и аппликативным языкам. К объектно-ориентированным языкам относятся C++, Object Pascal, Java.

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

    Первые языки программирования

    В пятидесятые годы двадцатого века с появлением компьютеров на электронных лампах началось бурное развитие языков программирования. Компьютеры, стоившие в то время значительно дороже, чем разработка любой программы, требовали высокоэффективного кода. Такой код разрабатывался вручную на языке Ассемблер. В середине 50-х годов под руководством Джона Бэкуса для фирмы IBM был разработан алгоритмический язык программирования FORTRAN. Несмотря на то, что уже существовали разработки языков, выполняющие преобразование арифметических выражений в машинный код, создание языка FORTRAN (FORmula TRANslator), предоставляющего возможность записи алгоритма вычислений с использованием условных операторов и операторов ввода/вывода, стало точкой отсчета эры алгоритмических языков программирования.
    К языку FORTRAN предъявлялись требования cоздания высокоэффективного кода. Поэтому многие конструкции языка первоначально разрабатывались с учетом архитектуры IBM 407. Успех разработки этого языка привел к тому, что производители других вычислительных систем стали создавать свои версии трансляторов. С целью некоторой возможной на тот момент унификации языка язык FORTRAN IV, разработанный в 1966 году, стал первым стандартом, именуемым FORTRAN 66.
    Как альтернатива языку FORTRAN, первоначально ориентированному на архитектуру IBM, под руководством Питера Наура в конце 50-х годов был разработан язык ALGOL (ALGOrithmic Language). Основной целью, преследуемой разработчиками этого языка, была независимость от конкретной архитектуры вычислительной системы. Кроме того, создатели языка ALGOL стремились разработать язык, удобный для описания алгоритмов и применяющий систему обозначений, близкую к той, что принята в математике.
    Языки FORTRAN и ALGOL были первыми языками, ориентированными на программирование вычислений.
    Язык PL/I, первые версии которого появились в начале 60-х годов, был первоначально ориентирован на IBM 360 и расширял возможности языка FORTRAN некоторыми средствами языка COBOL, разработанного в эти же годы.
    Несмотря на определенную популярность языка PL/I у программистов, работавших на компьютерах IBM и машинах серии ЕС, в настоящее время он представляет чисто теоретический интерес.

    В конце 60-х годов под руководством Найарда и Дала был разработан язык Simula-67, использующий концепцию пользовательских типов данных. Фактически это первый язык, применяющий понятие классов.

    В середине 70-х годов Вирт предложил язык Pascal, который сразу стал широко использоваться. В это же время по инициативе Министерства обороны США началась работа по созданию языка высокого уровня, получившего название Ada – в честь Ады Лавлейс, программистки и дочери лорда Байрона. Создание языка началось с определения требований и выработки спецификаций. Над проектом работали четыре независимые группы, но все они использовали как основу язык Pascal. В начале 80-х годов был разработан первый промышленный компилятор языка Ada.

    Универсальный язык программирования С был разработан в середине 70-х годов Денисом Ритчи и Кеном Томпсоном. Этот язык стал популярным языком системного программирования и в свое время использовался для написания ядра операционной системы UNIX. Стандарт языка С начал разрабатываться рабочей группой института стандартов ANSI в 1982 году. Международный стандарт языка С принят в 1990 году. Язык С лег в основу разработки языков программирования C++ и Java.

    Наряду с алгоритмическими языками параллельно развивались и языки, предназначаемые для обработки деловой информации, а также языки искусственного интеллекта. К первым относится язык COBOL (COmmon Business Oriented Language), а ко вторым – языки LISP (LISt Processing) и Prolog. Язык LISP, разработанный в 60-х годах под руководством Дж. Маккарти, был первым функциональным языком обработки списков, который нашел широкое применение в теории игр.

    С появлением персональных компьютеров языки стали составными частями интегрированных сред разработки. Появились языки, применяемые в различных офисных программах, например VBA (Visual Basic for Application).

    В 90-х годах с распространением сети Интернет расширяется возможность распределенной обработки данных, что отражается и на развитии языков программирования. Появляются языки, ориентированные на создание серверных приложений, такие как Java, Perl и PHP, языки описания документов – HTML и XML. Традиционные языки программирования С++ и Pascal также претерпевают изменения: под языком программирования начинает пониматься не только функциональность самого языка, а также библиотеки классов, предоставляемые средой программирования. Акцент со спецификации самих языков программирования переносится на стандартизацию механизмов взаимодействия распределенных приложений. Появляются новые технологии – COM и CORBA, специфицирующие взаимодействие распределенных объектов.

    Среда проектирования

    С развитием языков программирования совершенствовались и средства разработки программ – от режима командной строки до интегрированной среды проектирования. Такая среда предоставляет удобный графический интерфейс разработки и большой спектр сервисов, включающих управление версиями хранимых данных, утилиты просмотра и управления информацией, библиотеки классов, мастера создания шаблонов приложений и т.п.
    Компилятор языка программирования выступает как составная часть среды проектирования. Сама программа наряду с конструкциями, предусмотренными стандартом, как правило, использует библиотечные функции и классы, предоставляемые средой проектирования. Так, интегрированная среда разработки VisualStudio.NET содержит библиотеку классов MFC (Microsoft Foundation Classes), значительно упрощающую процесс разработки приложений, использующих оконный интерфейс.
    Интегрированная среда проектирования VisualStudio.NET позволяет создавать и компилировать приложения на языках C++, C#, Visual Basic и VisualJ. Для разработки приложений на языке С++ предназначается также среда CBuilder.
    Для проектирования приложений на языке Object Pascal используется интегрированная среда проектирования Delphi.
    Наиболее удобной средой разработки программ на языке Java является интегрированная среда проектирования JBuilder. Среда проектирования

    Стандартизация языков программирования

    Концепция языка программирования неотрывно связана с его реализацией. Для того чтобы компиляция одной и той же программы различными компиляторами всегда давала одинаковый результат, разрабатываются стандарты языков программирования. Существует ряд организаций, целенаправленно занимающихся вопросами стандартизации. Это Американский национальный институт стандартов ANSI (American National Standards Institute), Институт инженеров по электротехнике и электронике IEEE (Institute of Electrical and Electronic Engineers), Организация международных стандартов ISO (International Organization for Standardization).
    Как правило, при создании языка выпускается частный стандарт, определяемый разработчиками языка. Если язык получает широкое распространение, то со временем появляются различные версии компиляторов, которые не точно следуют частному стандарту. В большинстве случаев идет расширение зафиксированных первоначально возможностей языка. Для приведения наиболее популярных реализаций языка в соответствие друг с другом разрабатывается согласительный стандарт. Очень важным фактором стандартизации языка программирования является своевременность появления стандарта – до широкого распространения языка и создания множества несовместимых реализаций. В процессе развития языка могут появляться новые стандарты, отражающие современные нововведения. Так, язык FORTRAN первоначально был стандартизирован в 1966 году. В результате был издан стандарт FORTRAN 66. Далее этот стандарт несколько раз пересматривался (в 1977 году был выпущен FORTRAN 77, затем появился и FORTRAN 90).
    Язык Java, ставший в последнее время весьма распространенным, постепенно был значительно расширен и модифицирован: новая спецификация получила название Java 2.
    В процессе развития языка некоторые его конструкции и функции устаревают. Однако с целью обратной совместимости новые версии должны поддерживать и все устаревающие возможности. Это ведет к "разбуханию" компиляторов. В последнее время в реализациях введено понятие не рекомендуемой и устаревшей возможности. В первом случае следующий стандарт еще будет поддерживать не рекомендуемую возможность, но может перевести ее в категорию устаревшей. Во втором случае стандарт может исключить поддержку возможности, объявленной ранее как устаревшая. Введение не рекомендуемых и устаревших возможностей предоставляет разработчикам временной интервал, в течение которого они могут модифицировать код в соответствии с новыми требованиями стандарта.

    Введение в программирование

    НБФ-грамматика

    Грамматикой называется формальное описание синтаксиса языка программирования.
    Грамматика определяется набором правил (называемых иногда правилами подстановки), определяющих формирование из лексем достоверных программ.
    Формальная грамматика использует строгую систему обозначений. Существуют различные типы грамматик. НБФ-грамматика является контекстно-свободной грамматикой. Эта грамматика использует НБФ-нотации, предложенные Джоном Бэкусом в конце 50-х годов для описания синтаксиса языка ALGOL.
    Простая НБФ-нотация позволяет описывать все достоверные конструкции языка программирования, используя следующие символы:
  • символ ::= имеет значение "определяется как" и предшествует указанию всех допустимых значений описываемой синтаксической единицы;
  • символ | имеет значение "или" и используется для перечисления альтернативных вариантов;
  • пара символов < > ограничивает имя синтаксической единицы, называемой также нетерминальным символом или синтаксической категорией.

  • Значения, указываемые вне скобок < >, называются терминальными символами.
    НБФ-грамматика состоит из набора правил (называемых иногда металингвистическими формулами или продукциями), записываемых при помощи НБФ-нотации.
    Например:
    <цифра>::= 0|1|2|3|4|5|6|7|8|9 <целочисленное значение> ::= цифра | цифра < целочисленное значение>
    В данном примере символы 0, 1, 2, 3 и т.д. являются терминальными символами.
    При построении грамматики, описывающей язык программирования, выделяется начальный нетерминальный символ, определяющий конструкцию "программа".
    Существуют порождающие и распознающие грамматики. Порождающая грамматика генерирует множество цепочек терминальных символов из начального символа, а распознающая грамматика используется для построения по цепочке символов дерева грамматического разбора, ведущего к начальному символу.
    Можно сказать, что грамматика состоит из множества терминальных и нетерминальных символов, начального нетерминального символа и набора правил.
    В 1959 году Ноам Хомский предложил следующую классификацию грамматик:

  • регулярные грамматики, используемые для построения лексических анализаторов;
  • контекстно-свободные грамматики, используемые для построения дерева грамматического разбора. К этому типу относятся НБФ-грамматики;
  • контекстно-зависимые грамматики, представляемые набором правил типа x->y, в которых х может быть любой цепочкой нетерминальных символов, а y – цепочкой терминальных и нетерминальных символов. Этот тип грамматик намного сложнее контекстно-свободных грамматик и не имеет столь широкого применения при моделировании языков программирования;
  • грамматики с фразовой структурой, реализуемые набором правил типа x->y, в которых х может быть любой цепочкой нетерминальных символов, а y – цепочкой терминальных и нетерминальных символов (при этом нет никаких ограничений на длину получаемых цепочек символов). Большинство таких грамматик являются неразрешимыми и не имеют практического интереса.


  • Процесс трансляции

    Программу, написанную на языке программирования высокого уровня, называют исходной программой, а каждую самостоятельную программную единицу, образующую данную программу, - программным модулем. Для преобразования исходной программы в ее выполняемую форму (выполнимый файл) транслятор выполняет некоторую последовательность действий. Эта последовательность зависит как от языка программирования, так и от конкретной реализации самого транслятора. В ходе трансляции важно не просто откомпилировать программу, а получить при этом достаточно эффективный код.
    В процессе трансляции выполняется анализ исходной программы, а затем синтез выполнимой формы данной программы. В зависимости от числа просмотров исходной программы, выполняемых компилятором, трансляторы разделяются на однопроходные, двухпроходные и трансляторы, использующие более двух проходов.
    К достоинствам однопроходного компилятора можно отнести высокую скорость компиляции, а к недостаткам - получение, как правило, не самого эффективного кода.
    Широкое распространение получили двухпроходные компиляторы. Они позволяют при первом проходе выполнить анализ программы и построить информационные таблицы, используемые при втором проходе для формирования объектного кода.
    На рисунке 2.1 представлены основные этапы, выполняемые в процессе трансляции исходной программы.
    Процесс трансляции
    Рис. 2.1.  Основные этапы трансляции программы
    Фаза анализа программы состоит из:
  • лексического анализа;
  • синтаксического анализа;
  • семантического анализа.

  • При анализе исходной программы транслятор последовательно просматривает текст программы, представимой как набор символов, выполняя разбор структуры программы.
    На этапе лексического анализа выполняется выделение основных составляющих программы – лексем. Лексемами являются ключевые слова, идентификаторы, символы операций, комментарии, пробелы и разделители. Лексический анализатор не только выделяет лексемы, но и определяет тип каждой лексемы. При этом на этапе лексического анализа составляется таблица символов, в которой каждому идентификатору сопоставлен свой адрес.
    Это позволяет при дальнейшем анализе вместо конкретного значения (строки символов) использовать его адрес в таблице символов.

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

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

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

    К наиболее общим задачам, решаемым семантическим анализатором, относятся:

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


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

    На фазе синтеза программы производится:

  • генерация кода;
  • редактирование связей.


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

    Так, процесс генерации кода является неотъемлемой частью фазы синтеза программы, а необходимость выполнения редактора связей зависит от конкретного языка программирования. Следует учесть, что на практике термин "генерация кода" часто применяют ко всем действиям фазы синтеза программы, ведущим к получению выполнимой формы программы.

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

    Расширенная НБФ-нотация

    При описании правил НБФ-грамматики с применением стандартной НБФ-нотации синтаксические конструкции, имеющие необязательные или альтернативные элементы, выглядят при всей их простоте достаточно громоздко. Расширенная НБФ-нотация вводит ряд дополнительных элементов, позволяющих значительно улучшить наглядность представления правил НБФ-грамматики.
    Расширенная НБФ-нотация вводит следующие дополнительные элементы:
  • необязательные элементы указываются заключенными в квадратные скобки;
  • альтернативные элементы, указываемые через символ вертикальной черты, также могут являться необязательными элементами, заключаемыми в квадратные скобки;
  • последовательность нескольких однотипных элементов обозначается заключением элемента в фигурные скобки, за которыми указывается символ звездочка ({<целое>}*).

  • Расширенная НБФ-нотация

    Трансляторы

    Программа, написанная на языке высокого уровня, перед исполнением должна быть преобразована в программу на "машинном языке". Такой процесс называется трансляцией, или компиляцией. По типу выходных данных различают два основных вида трансляторов:
  • компилирующие окончательный выполнимый код;
  • компилирующие интерпретируемый код, для выполнения которого требуется дополнительное программное обеспечение.

  • Окончательным выполнимым кодом являются приложения, реализованные как EXE-файлы, DLL-библиотеки, COM-компоненты. К интерпретируемому коду можно отнести байт-код JAVA-программ, выполняемый посредством виртуальной машины JVM.
    Языки, формирующие окончательный выполнимый код, называются компилируемыми языками. К ним относятся языки С, C++, FORTRAN, Pascal. Языки, реализующие интерпретируемый код, называются интерпретируемыми языками. К таким языкам относятся язык Java, LISP, Perl, Prolog.
    В большинстве случаев код, получаемый в результате процесса трансляции, формируется из нескольких программных модулей. Программным модулем называется определенным образом оформленный код на языке высокого уровня. Процесс трансляции в этом случае может выполняться как единое целое – компиляция и редактирование связей, или как два отдельных этапа – сначала компиляция объектных модулей, а затем вызов редактора связей, создающего окончательный код. Последний подход более удобен для разработки программ. Он реализован в трансляторах языков С и С++.
    Объектный код, создаваемый компилятором, представляет собой область данных и область машинных команд, имеющих адреса, которые в дальнейшем "согласуются" редактором связи (иногда называемым загрузчиком). Редактор связи размещает в едином адресном пространстве все по отдельности откомпилированные объектные модули и статически подключаемые библиотеки.
    Будем называть выполнимой формой программы код, получаемый в результате трансляции исходной программы.

    Введение в программирование

    Операции

    При вычислении выражений учитывается приоритет операций: сначала выполняются операции с более высоким приоритетом.
    Вычисление выражений, имеющих операции с одинаковым приоритетом, производится в соответствии с правилом сочетательности, которое определяет порядок выполнения таких операций. В языке С сочетательность операций применяется как слева направо, так и справа налево (как и при вычислении возведения в степень). Порядок вычисления справа налево означает, что выражение x** 2**4 трактуется как x**(2**4).
    В следующей таблице приведены в убывающем порядке уровни приоритета операций языка С.

    Таблица 3.1. Уровни приоритета операций языка С.Уровни приоритетаОперацииПорядок выполнения операций
    Скобки( ), [ ]слева направо
    Индексы, вызов функцийx[i], fun()слева направо
    Постфиксный инкремент и декремент++, --слева направо
    Префиксный инкремент и декремент++, --слева направо
    Унарный минус-слева направо
    Поразрядное отрицание (NOT)~слева направо
    Размер объектаsizeofслева направо
    Логическое отрицание!слева направо
    Получение адреса и разименование&, *справа налево
    Явное приведение типа(any_type)слева направо
    Умножение, деление, деление по модулю*, / , %слева направо
    Сложение, вычитание+, -слева направо
    Сдвиг влево, сдвиг вправо<<, >>слева направо
    Сравнение (меньше, больше, меньше или равно, больше или равно)<, >, <=, >=слева направо
    Сравнение (тождественное равенство, неравенство)==, !=слева направо
    Поразрядное логическое И&слева направо
    Поразрядное исключающее ИЛИ (XOR)^слева направо
    Поразрядное логическое ИЛИ|слева направо
    Логическое И (AND)&&слева направо
    Логическое ИЛИ (OR)||слева направо
    Условная операция?:справа налево
    Операция перед присваиванием=, +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, |=справа налево

    Операции AND, OR, NOT и XOR относятся к логическим операциям. Следующая таблица показывает результаты применения логических операций.

    Таблица 3.2. Результаты применения логических операций.xyx && y (x AND y)x || y (x OR y)! x (NOT x)x ^ y (x XOR y)
    0 (false)0 (false)0010
    0 (false)1 (true)0111
    1 (true)0 (false)0101
    1 (true)1 (true)1100


    Единственной операцией, имеющей три операнда, является операция "условие" (называемая также условной операцией).

    Условная операция имеет следующий формальный синтаксис:

    (expr_log) ? expr1:expr2.

    Если выражение expr_log принимает значение true, то условная операция возвращает значение expr1, а если false, то значение expr2.

    Например:

    // x примет значение 1, если y>z. x=(y>z)? 1:0;

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

    value<>count_of_position.

    Например, выражение 9<<2 вычисляется следующим образом: число 9 имеет в двоичном представлении значение 001001 (118) и при сдвиге его на два разряда влево получается значение 100100 (448).

    Операции инкремента и декремента соответственно увеличивают или уменьшают значение операнда на 1. Различают постфиксный и префиксный инкремент и декремент. Например, выражение x++ возвращает значение переменной х, а затем увеличивает его на 1, а выражение ++x увеличивает значение x на 1 и возвращает его.

    Операция присваивания в различных языках имеет разное обозначение. Так, в языках С, C++, Java операция присваивания обозначается символом =. Например, x=y+z;. Язык С позволяет в одном операторе указывать несколько операций присваивания. Например: x1=x2=y+z;. В языках Pascal и ALGOL операция присваивания указывается символами :=. Например: x:=y+z;. В языке LISP операция присваивания обозначается функцией SETQ (например, (SETQ x (PLUS y z))).

    Операторы цикла

    Операторы цикла наряду с механизмом рекурсии выражают форму повторения последовательности действий.
    Языки программирования, как правило, имеют несколько форм оператора цикла.
    В языке С++ предусмотрено три формы оператора цикла:
  • for
  • do
  • while.

  • Цикл for выполняется заданное число раз, а проверка условия принадлежности счетчика цикла заданному диапазону производится до выполнения операторов, указанных в цикле.
    Оператор do выполняется до тех пор, пока условие цикла остается истинным, а проверка условия цикла производится после выполнения операторов, указанных в цикле.
    Оператор while выполняется до тех пор, пока условие цикла остается истинным, а проверка условия цикла производится до выполнения операторов, указанных в цикле.
    Принято считать, что любой оператор цикла состоит из двух частей:
  • заголовка цикла, определяющего число выполнений цикла;
  • тела цикла, содержащего последовательность выполняемых операторов (в большинстве случаев указываемую как один составной оператор).

  • Реализация операторов цикла с конечным числом повторений отличается от реализации циклов с бесконечным повторением или повторением, основанным на некоторых данных. При реализации цикла с конечным числом повторений выделяется специальная область памяти для хранения этого значения. Цикл for также может относиться как к циклам с конечным числом повторений ( for (i=1; i<50; i++){cout<

    Операторы исключений

    Некоторые языки программирования позволяют реализовывать обработку ошибок, называемых исключениями, используя операторы исключений. Код, который может инициировать исключение, заключается в специальный оператор try-catch. При этом ключевое слово catch определяет действия, выполняемые в случае возникновения определенного исключения. Исключение может инициироваться программно или оператором throw (бросок исключения). Некоторые языки программирования позволяют передавать обработку исключения вызывающему методу (так, в языке Java в сигнатуре метода можно ключевым словом throws указать список исключений, при возникновении которых управление будет возвращено вызывающей программе). Операторы исключений

    Операторы перехода

    Для выхода из бесконечных циклов или подпрограмм используются операторы перехода. В языке C++ реализованы четыре оператора перехода:
  • break – прерывает выполнение цикла, завершая его;
  • continue – завершает текущую итерацию выполнения цикла;
  • return – определяет выход из функции;
  • goto – оператор безусловного перехода на метку.


  • Операторы выбора

    К операторам выбора относятся:
  • if – условный оператор;
  • switch – переключатель.

  • Операторы выбора осуществляют ветвление. Оператор if в зависимости от значения выражения-условия позволяет выполнить только одну из двух указанных последовательностей операторов (в большинстве языков программирования такая последовательность операторов указывается как один составной оператор). Существуют формы оператора if, позволяющие задавать вместо второй выполняемой последовательности операторов условие (if-elseif-then- elseif-then).
    Оператор switch в зависимости от значения вычисляемого выражения позволяет выполнить одну из нескольких указанных последовательностей операторов.
    Например:
    switch (i): { case 0: case 1: // последовательность операторов break; case 2: // последовательность операторов break; default: }
    Реализация оператора if достаточно проста: как правило, процессор поддерживает команды перехода и ветвления.
    Реализация оператора switch может быть выполнена в виде таблицы перехода, состоящей из команд безусловного перехода на соответствующие фрагменты кода. Вычисляемое выражение оператора switch в этом случае преобразовывается в значение сдвига по таблице перехода, определяющее выполняемую команду.

    Определение последовательности действий в выражениях

    Выражение состоит из операций, операндов и функций (функции можно рассматривать как особый тип операции). Операндами могут выступать переменные и константы. Операторы, определяющие операции, могут быть унарными и бинарными.
    Унарный оператор действует только на один операнд, а бинарный оператор – на два операнда.
    Синтаксис выражения можно представить в виде дерева: вершиной дерева является последняя выполняемая операция, узлы описывают промежуточные операции, а листья указывают данные (переменные или константы).
    На рисунке 3.1 показано древовидное представление вычисления выражения (x*y)-x*(-(x**2)+(y-0.3)).
    Определение последовательности действий в выражениях
    Рис. 3.1.  Древовидное представление выражения
    Для представления выражения в линейной форме применяются следующие формы записи:
  • префиксная запись;
  • постфиксная запись;
  • инфиксная запись.

  • В префиксной записи, называемой также польской префиксной записью, сначала записывается символ операции, а затем по порядку слева направо записываются операнды. Так, выражение (z+2)*(x+y) в префиксной записи будет иметь следующий вид: * + z 2 + x y. Польская префиксная запись не содержит скобок и позволяет однозначно определять порядок вычисления выражения.
    Язык LISP для представления выражений использует префиксный тип записи, называемый кембриджской польской записью. Такая запись в отличие от польской записи содержит скобки, ограничивающие операнды, на которые действует операция. Таким образом, в кембриджской польской записи выражение представляет собой множество вложенных подвыражений, ограниченных скобками.
    Например:
    * (+ (z 2) +(x y))
    В постфиксной записи, называемой также обратной польской записью или суффиксной записью, символ операции записывается после операндов. Выражение (z+2)*(x+y) в постфиксной записи будет иметь следующий вид: z 2 + x y + *.
    Третьим типом записи выражений является инфиксная запись, используемая для представления выражений как в математике, так и в языках программирования. Инфиксная запись - это стандартный способ записи выражений, при котором символ операции указывается между операндами. Однако инфиксная запись не позволяет представлять унарные операции.
    Наиболее простым представлением выражения с точки зрения процесса трансляции является постфиксная запись. Однако префиксная запись более удобно обеспечивает обработку функций. Кроме того, префиксная запись позволяет вычислить выражение за один просмотр транслятора, но существенным недостатком при этом является то, что для каждой операции требуется предварительно знать число обрабатываемых ею операндов (унарная, бинарная, функция).

    Составные операторы

    Каждая из основных форм управления последовательностью действий имеет в различных языках программирования свои, в значительной степени синтаксически схожие, операторы языка программирования.
    Для создания сложных управляющих композиций иногда последовательность операторов необходимо указывать как один оператор. Для этой цели служит составной оператор. Синтаксически составной оператор может быть указан ключевыми словами begin end (язык Pascal) или фигурными скобками {} (языки C++, Java, Perl).

    Структурное программирование

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

  • Алгоритм выполнения структурированной программы может быть представлен в виде блок-схемы. Такая блок-схема может содержать три типа узлов:
  • функциональные узлы;
  • узлы вычисления условия;
  • узлы соединения ветвей.

  • Изображение этих узлов представлено на следующей схеме.
    Структурное программирование
    Рис. 3.2.  Типы узлов и соответствующие блок-схемы
    Правильная структурированная программа представляется блок-схемой, в которой существует только одна входящая и одна исходящая дуга, в любой узел можно попасть от входящей дуги и из любого узла можно попасть к выходящей дуге.

    Управляющие структуры

    Управление последовательностью действий в языках программирования может быть представлено некоторой управляющей структурой. Такая структура называется неявным управлением в том случае, если последовательность действий определяется естественным образом (например, выполнение программы идет с первого оператора и т.д.). Управляющая структура представляет собой явное управление в том случае, если для изменения порядка выполнения действий используются какие-либо операторы или иные синтаксические конструкции. Основными управляющими структурами принято считать:
  • операторы;
  • выражения;
  • подпрограммы.

  • В языках логического программирования управляющие структуры могут представляться несколько иначе. Так, в языке Prolog модель управления последовательностью действий вместо операторов использует такие категории, как факты, правила и запросы.

    Введение в программирование

    Определение и активация подпрограмм

    Программу можно рассматривать как некоторую иерархическую структуру, состоящую из одной главной программы и множества произвольным образом вызываемых подпрограмм. Точка вызова подпрограммы является и точкой возврата из подпрограммы.
    Для выполнения любого выражения транслятор преобразует его в некоторый код, который или может быть сразу аппаратно интерпретируем (машинный язык) или программно интерпретируем (использование интерпретатора).
    Для выполнения подпрограммы производится ее активация, в результате чего создаются:
  • сегмент кода, содержащий выполняемый код и константы;
  • сегмент данных, называемый также записью активации, содержащей локальные переменные и параметры.

  • Сегмент кода представляет собой неизменяемую часть, статически сохраняемую в памяти, а сегмент данных создается заново при каждом выполнении подпрограммы.
    Каждая активация подпрограммы использует один единожды созданный сегмент кода.
    Подпрограмма может быть реализована как процедура или функция. Процедура - это подпрограмма, выполняющая определенные действия и завершающаяся без возврата значения определенного типа.
    Результатом выполнения функции всегда является возврат некоторого значения.
    При выполнении программы текущая выполняемая команда идентифицируется двумя указателями:
  • CIP-указатель (current instruction pointer) является указателем текущей команды сегмента кода;
  • CEP-указатель (current environment pointer) является указателем текущей записи активации. CEP-указатель иногда также называется указателем текущей среды, так как определяет среду всех объектов данных, используемых подпрограммой.

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

    Последовательный вызов подпрограмм

    Запись активации для главной программы создается или перед началом выполнения программы или в процессе трансляции одновременно с формированием сегмента кода.
    Перед переходом на подпрограмму текущие значения CIP- и CEP-указателей сохраняются. Выполнение программы начинается с присваивания CEP-указателю адреса записи активации, а CIP-указателю - ссылки на первую команду сегмента кода главной программы. При каждом вызове подпрограммы создается новая запись активации этой подпрограммы, и значение CEP-указателя устанавливается на эту запись активации, а значение CIP-указателя - на первую команду фрагмента кода подпрограммы.
    При возврате из подпрограммы восстанавливаются сохраненные значения CIP- и CEP-указателей и удаляется запись активации.
    Место сохранения значений CIP-указателя и CEP-указателя иногда называют точкой возврата. Точка возврата представляет собой системный объект, сохраняемый, как правило, в записи активации.
    При последовательном вызове подпрограммы (реализуемом иногда как копирование подпрограммы) в процессе выполнения может создаваться множество записей активации подпрограммы, но в каждый отдельный момент времени хранится и используется только одна запись активации, т.е. перед созданием новой записи активации прежняя запись активации должна быть удалена.
    Иногда в реализациях для достижения наибольшего быстродействия жертвуют некоторым количеством требуемой памяти: место под запись активации выделяется статически при компиляции (в фрагменте кода) и при каждом вызове происходит только повторная инициализация записи активации. В этом случае никакая подпрограмма не может одновременно иметь более одной записи активации, что значительно сужает возможности программиста. Такая модель выполнения присуща большинству трансляторов языка FORTRAN.
    Для аппаратной реализации вызова подпрограммы с заранее фиксированной записью активации достаточно только CIP-указателя, сохраняемого командой перехода с возвратом.
    Если место для записи активации должно выделяться динамически, то это, как правило, реализуется с помощью стека.

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

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

    На рисунке 4.1 представлена организация памяти, используемая при выполнении программы на языке С.

    Последовательный вызов подпрограмм
    Рис. 4.1.  Организация памяти, используемая при выполнении программы на языке С.

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

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

    Рекурсивный вызов подпрограмм

    Применение стека для хранения записей активации позволяет реализовывать не только последовательный вызов подпрограмм, но и рекурсивный вызов.
    Рекурсивным вызовом подпрограммы называется вызов подпрограммы из самой себя. При n вызовах подпрограммы A в стек будет последовательно добавлено n записей активации этой подпрограммы. Последний вызов подпрограммы A будет завершен первым, и его запись активации будет первой удалена из стека.
    Примером использования рекурсии может служить программа вычисления факториала n! =(n*(n-1)!), 0!=1.
    Пример подпрограммы на языке С:
    int factoria(int n) { if (n) return n* factoria(n-1); else return 1; }
    В некоторых случаях без применения рекурсии задачу решить практически невозможно. Хорошо известен пример программирования алгоритма ханойских башен. Условия задачи состоят в следующем: есть три башни, первая башня состоит из колец, диаметр которых увеличивается сверху вниз. Задача заключается в программировании алгоритма, обеспечивающего перемещение колец с первой башни на вторую по одному с возможным использованием вспомогательной третьей башни таким образом, чтобы все кольца оказались на второй башне и их диаметр увеличивается сверху вниз. Алгоритм решения этой задачи посредством рекурсии состоит в предположении, что эта задача решена для n-1 кольца. Тогда, если при n=1 решение задачи очевидно, то есть решение и для n колец.
    Пример подпрограммы на языке С++, реализующей алгоритм ханойских башен:
    #include "stdafx.h" #include void tower_3(int n, int m, int k); int main(int argc, _TCHAR* argv[]) { tower_3 (3,1,3); return 0; }
    void tower_3(int n, int m, int k){ /* n - число перемещаемых колец m - башня, с которой выполняется перемещение k - башня, на которую выполняется перемещение */
    if (n==1) { //Последнее очевидное перемещение return ;}
    tower_3(n-1,m,6-m-k); /* 6-m-k определяет номер вспомогательной башни, m - номер башни, с которой выполняется перемещение */
    std::cout<<" from "<< m << " to "<< k << " n= "< На рисунке 4.2 приведен пример выполнения алгоритма ханойских башен для трех колец (n указывает количество перекладываемых колец).
    Рекурсивный вызов подпрограмм
    Рис. 4.2.  Результат рекурсивного вызова процедуры.
    Одним из первых языков программирования, допускавших рекурсию, являлся ALGOL 60. Раньше принципы реализации записей активации трансляторами языка FORTRAN не позволяли применять рекурсию, но последняя версия компилятора языка FORTRAN 90 это допускает.
    Подпрограммы A и B называются взаимно рекурсивными, если подпрограмма A вызывает B, а подпрограмма B вызывает A.
    Языки программирования, для которых традиционно используются однопроходные компиляторы, для реализации взаимной рекурсии должны вводить предварительное определение подпрограммы. Это объясняется тем, что при взаимно рекурсивном вызове подпрограмм A и B, в момент вызова B из A подпрограмма B должна быть уже определена, а в момент вызова A из B подпрограмма A должна быть определена. Такой механизм используется в языках Pascal и Ada.
    Язык Pascal не требует указания сигнатуры функции или процедуры в том случае, если ее определение расположено в коде программы до ее вызова. В противном случае используется предварительное определение, указываемое ключевым словом forward.
    На рисунке 4.3 приведен код модуля на языке Pascal (созданного в среде Delphi), иллюстрирующий предварительное объявление функции A.
    Рекурсивный вызов подпрограмм
    Рис. 4.3.  Предварительное объявление функции.
    Следует отметить, что компиляция программ, удовлетворяющих стандарту языка программирования, различными трансляторами может создавать различный выполнимый код. При этом очень часто компиляторы несколько "расширяют" диапазон возможностей, предоставляемых стандартом языка программирования. Такая ситуация будет приводить к ограничению использования "расширенного" синтаксиса программы с другими компиляторами. Рекурсивный вызов подпрограмм

    Введение в программирование

    Блочно-структурированные языки программирования

    В блочно-структурированных языках программирования программа записывается как множество иерархически вложенных блоков определенной структуры.
    Блочно-структурированные языки программирования можно подразделить на строго блочно-структурированные языки и просто блочно-структурированные языки.
    В строго блочно-структурированных языках в начале каждого блока располагается область объявлений, а за ней следует фрагмент кода. Иначе говоря, в строго блочно-структурированных языках программирования не допускается объявление переменных в любом месте фрагмента кода.
    К строго блочно-структурированным языкам программирования относятся языки ALGOL 60, Pascal, PL/I.
    Каждый блок в блочно-структурированном языке программирования вводит новую среду локальных ссылок.
    Следующий пример иллюстрирует блочную структуру программы на языке Pascal.
    program Project1; procedure P1(); procedure P2(); {Вложенная процедура} var i:Integer; begin end; begin {Код процедуры P1} end; begin {Код главной программы Project1} end.
    В языке Object Pascal по умолчанию приложения создаются как набор модулей, подключаемых ключевым словом uses. Следующий пример иллюстрирует блочную структуру программы на языке Object Pascal, представленную в виде одного модуля.
    program Project2; {Начало программы} uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; {$R *.res} {$R *.dfm} {Имя DFM-файла должно совпадать с именем модуля (блока). } {Для получения единого модуля на языке Object Pascal при автоматическом создании приложения в среде Delphi файл Unit1.dfm следует переименовать в Project2.dfm, а код модуля Unit1.pas перенести в модуль Project2.pas}
    type {Объявление нового типа окна формы TForm1 } TForm1 = class(TForm) Button1: TButton; Button2: TButton; ListBox1: TListBox; Edit1: TEdit; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure ListBox1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var {Начало области объявлений } Form1: TForm1; i: Integer; procedure TForm1.Button1Click(Sender: TObject); begin Edit1.Text:='Button1'; end; procedure TForm1.Button2Click(Sender: TObject); var i:Integer; procedure P1(); {Вложенная процедура} var i:Integer; begin i:=5; Edit1.Text:= Edit1.Text+' i= ' + IntToStr(i); end; begin Edit1.Text:='Button2'; i:=0; P1 (); end; procedure TForm1.ListBox1Click(Sender: TObject); begin Edit1.Text:='ListBox1'; end; begin {Начало выполнения программы} Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.

    Пример 5.1. Блочная структура программы на языке Object Pascal

    На рисунке 5.1 отображен результат выполнения приведенной выше программы (сделан щелчок мышью на кнопке Button2, инициирующий выполнение процедуры TForm1.Button2Click и вложенной процедуры P1).

    Блочно-структурированные языки программирования
    Рис. 5.1.  Окно формы

    К простым блочно-структурированным языкам относятся такие языки, как C и Java, позволяющие формировать область объявления переменных в любом месте блока.

    Современные языки программирования, такие как C++, Java, Object Pascal, относятся к блочно-структурированным языкам программирования, и при этом программы на этих языках могут состоять из нескольких блоков (программных модулей), расположенных на верхнем уровне иерархии.

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

    Блок может представлять собой:

  • программу (например, program end.),
  • фрагмент кода, заключенный в скобки блока (такие как begin end)
  • подпрограмму (например, procedure begin end;).


  • Начало программы} uses Windows, Messages,

    program Project2; { Начало программы} uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; {$R *.res} {$R *.dfm} {Имя DFM-файла должно совпадать с именем модуля (блока). } {Для получения единого модуля на языке Object Pascal при автоматическом создании приложения в среде Delphi файл Unit1.dfm следует переименовать в Project2.dfm, а код модуля Unit1.pas перенести в модуль Project2.pas}

    type {Объявление нового типа окна формы TForm1 } TForm1 = class(TForm) Button1: TButton; Button2: TButton; ListBox1: TListBox; Edit1: TEdit; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure ListBox1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var {Начало области объявлений } Form1: TForm1; i: Integer; procedure TForm1.Button1Click(Sender: TObject); begin Edit1.Text:='Button1'; end; procedure TForm1.Button2Click(Sender: TObject); var i:Integer; procedure P1(); {Вложенная процедура} var i:Integer; begin i:=5; Edit1.Text:= Edit1.Text+' i= ' + IntToStr(i); end; begin Edit1.Text:='Button2'; i:=0; P1 (); end; procedure TForm1.ListBox1Click(Sender: TObject); begin Edit1.Text:='ListBox1'; end; begin {Начало выполнения программы} Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.
    Пример 5.1. Блочная структура программы на языке Object Pascal
    Закрыть окно





    program Project2; {Начало программы}

    uses

    Windows, Messages, SysUtils, Variants,

    Classes, Graphics, Controls, Forms,

    Dialogs, StdCtrls;

    {$R *.res}

    {$R *.dfm} {Имя DFM-файла должно совпадать

    с именем модуля (блока). }

    { Для получения единого модуля на языке Object Pascal

    при автоматическом создании приложения в среде Delphi

    файл Unit1.dfm следует переименовать в Project2.dfm,

    а код модуля Unit1.pas перенести в модуль Project2.pas}

    type {Объявление нового типа окна формы TForm1 }

    TForm1 = class(TForm)

    Button1: TButton;

    Button2: TButton;

    ListBox1: TListBox;

    Edit1: TEdit;

    procedure Button1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

    procedure ListBox1Click(Sender: TObject);

    private

    { Private declarations }

    public

    { Public declarations }

    end;

    var {Начало области объявлений }

    Form1: TForm1;

    i: Integer;

    procedure TForm1.Button1Click(Sender: TObject);

    begin

    Edit1.Text:='Button1';

    end;

    procedure TForm1.Button2Click(Sender: TObject);

    var i:Integer;

    procedure P1(); {Вложенная процедура}

    var i:Integer;

    begin

    i:=5;

    Edit1.Text:= Edit1.Text+' i= ' + IntToStr(i);

    end;

    begin

    Edit1.Text:='Button2';

    i:=0;

    P1 ();

    end;

    procedure TForm1.ListBox1Click(Sender: TObject);

    begin

    Edit1.Text:='ListBox1';

    end;

    begin {Начало выполнения программы}

    Application.Initialize;

    Application.CreateForm(TForm1, Form1);

    Application.Run;

    end.

    Функции и процедуры

    Как уже было сказано в предыдущей лекции, подпрограмма в большинстве языков программирования может быть реализована двумя способами: как функция и как процедура.
    Если подпрограмма реализуется как функция, то она при завершении должна возвращать значение определенного типа (например, return 0;). Подпрограмма-функция может указываться в выражениях.
    Подпрограмма-функция также может быть передана подпрограмме в качестве фактического параметра, например,
    (procedure P1 (i: integer; function P2(j:integer):integer);).
    Помимо использования глобальных переменных, некоторые языки программирования позволяют делать локальные переменные подпрограмм доступными для других подпрограмм, выполняющихся вне текущей записи активации данной подпрограммы. Это может быть реализовано как экспорт данных (externs в языке С, uses в языке Pascal), и в таком случае экспортируемая локальная переменная должна быть доступна вне записи активации. Поэтому ее, как правило, размещают в сегменте кода подпрограммы.
    К способам реализации совместного использования данных относится и механизм явно организуемой общей среды. Все объекты данных, которые предполагается использовать в ряде подпрограмм, могут быть помещены в такую общую среду. Этот механизм реализуется в таких языках программирования, как С (переменные помечаются как extern), Ada (переменные указываются в пакете), FORTRAN (переменные задаются в блоке COMMON). В объектно-ориентированных языках программирования совместное использование данных может быть реализовано через модификаторы доступа переменных членов классов.
    Другие языки программирования (LISP, APL) для реализации совместного использования данных применяют механизм динамической области видимости, при котором выполняется восходящий поиск ассоциации для переменной (ассоциация для нелокальной переменной подпрограммы последовательно ищется во всех средах ссылок выполняемых ранее подпрограмм). Функции и процедуры

    Передача параметров

    Внешние данные в подпрограмме могут использоваться, если они являются глобальными объектами для данной подпрограммы или переданы ей в качестве параметров. В описании подпрограммы указываются формальные параметры, а в точке вызова подпрограммы задаются фактические параметры. Формальный параметр определяет тип передаваемого фактического параметра. Фактический параметр представляет собой выражение соответствующего типа.
    Различаются следующие способы передачи параметров: по ссылке, по имени, по значению, по значению-результату, по результату, по значению-константе. Набор допустимых способов передачи параметров зависит от конкретного языка программирования.
    При передаче параметров по ссылке в записи активации, создаваемой при выполнении подпрограммы, ассоциация для фактического параметра может формироваться в нелокальной среде ссылок (в зависимости от реализации компилятора). Так, при вызове подпрограммы для параметров, передаваемых по ссылке, формируются указатели, доступные как из вызывающей, так и из вызываемой подпрограммы. Таким образом, при изменении в вызываемой подпрограмме значения фактического параметра, переданного по ссылке, в вызывающей программе объект, соответствующий фактическому параметру, также будет изменен.
    При передаче параметров по имени в вызываемой подпрограмме до ее выполнения происходит замена формальных параметров на фактические. При этом значения фактических параметров вычисляются внутри вызываемой подпрограммы.
    При передаче параметров по значению в вызываемой подпрограмме создается псевдоним фактического параметра (копия фактического параметра), значение которого присваивается формальному параметру подпрограммы. При таком способе передачи параметров изменения, произведенные в вызванной процедуре над значением фактического параметра, будут не видны далее в вызывающей подпрограмме.
    При передаче параметров по значению-результату измененное значение фактического параметра возвращается вызывающей подпрограмме. Однако, в отличие от передачи параметров по ссылке, при данном способе сначала в момент вызова подпрограммы значение фактического параметра присваивается соответствующему формальному параметру вызываемой подпрограммы, и все изменения выполняются над формальным параметром, а не над ссылкой на фактический параметр.
    При завершении вызываемой подпрограммы текущее значение формального параметра присваивается обратно фактическому параметру. Такой тип передачи параметров был применен в языке ALGOL-W.

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

    При передаче параметров по значению-константе значение фактического параметра не может быть изменено. Такой способ передачи параметров может быть реализован и как частный случай передачи параметра по значению, и как передача параметра по ссылке на константное выражение, что однозначно гарантирует неизменность фактического параметра вызывающей подпрограммы.

    В большинстве случаев языки программирования используют один или два способа передачи параметров. Так, язык программирования С позволяет только передачу параметров по значению (ссылка реализуется как значение указателя). В языке программирования Pascal допускается два способа передачи параметров: по значению и по ссылке.

    В следующей таблице приведены фрагменты кода, иллюстрирующие способы передачи параметров в языках программирования С и Pascal.

    Способ передачи параметровPascalC
    Передача параметров по значению

    procedure P1(i: integer); begin i:=0; end;



    // Передача значения void P1(int i) {i=0; } //Вызов подпрограммы i=10; P1(i);

    Передача параметров по ссылке

    procedure P1(var i: integer); begin i:=0; end;



    // Передача указателя на значение void P1(int *i) { *i=*i+1;} //Вызов подпрограммы i=10; P1(&i);

    Существующие в настоящее время средства автоматической генерации кода вызова подпрограммы по описанию интерфейса вводят понятие входных и выходных параметров (помечаемых как in и out). При этом в зависимости от типа параметра и определения его как входного и/или выходного компилятор автоматически выбирает походящий для данной реализации способ передачи параметров.

    Управление данными

    При интерпретации выполняемого выражения, содержащего данные, компилятор должен однозначно "понимать" указываемые идентификаторами операнды выражения. Так, один и тот же идентификатор может в различных частях программы использоваться для обозначения разных данных. Идентификатор может быть меткой или именем подпрограммы. В первом случае при трансляции выражения компилятор должен инициировать сообщение об ошибке компиляции. В зависимости от того, указывает ли идентификатор на переменную или на константу компилятор также должен предпринимать различные действия.
    Имя в программе может быть простым или составным. К простым именам относятся имена переменных, имена подпрограмм, имена пользовательских типов данных. Составное имя ссылается на элемент некоторой структуры и записывается как простое имя и следующие за ним операции квалификации или индексации имени. Например, выражение array1[3] ссылается на третий элемент массива, а выражение record1.field2 ссылается на значение поля field2 структуры record1.
    Для управления данными конкретные идентификаторы подпрограммы должны быть сопоставлены конкретным объектам данных. Такое сопоставление иногда называется ассоциацией. В момент создания записи активации устанавливается множество ассоциаций, сопоставляющих идентификаторы с текущими объектами данных. Такое множество ассоциаций определяет среду ссылок подпрограммы.
    Среда ссылок подпрограммы включает среду глобальных ссылок, среду локальных ссылок, среду нелокальных ссылок и среду предопределенных ссылок.
    Среда локальных ссылок образуется локальными переменными, формальными параметрами, а также подпрограммами, определенными внутри текущей подпрограммы.
    Среда глобальных ссылок формируется ассоциациями, которые созданы при активации главной программы. Среда нелокальных ссылок содержит как среду глобальных ссылок, так и множество ассоциаций, сформированных для доступных далее в программе, но еще не созданных переменных.
    Область видимости ассоциации в подпрограмме определяется включением этой ассоциации в среду ссылок подпрограммы.
    При этом если имело место переопределение глобального идентификатора локальным идентификатором, то ассоциация для глобального идентификатора исключаются из среды глобальных ссылок подпрограммы.

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

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

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

    int1=5*x; int2=8*y;

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

    Под статической областью видимости понимается фрагмент кода программы, в котором идентификатор ссылается на конкретный объект.

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

    Введение в программирование

    Константы в языке Object Pascal

    Объявление переменных выполняется в секции, начинающейся с ключевого слова var. Ключевое слово const предназначено для объявления констант.
    Константами могут быть простые значения или значения типа записи, массива, функции и указателя.
    При объявлении константного указателя его сразу необходимо инициализировать.
    Инициализация константного указателя может быть выполнена тремя способами:
  • определением адреса глобальной переменной с использованием оператора @;
  • указанием адреса равного nil;
  • заданием значения константы типа PChar или PWideChar.

  • Например:
    const PI: ^Integer = @i1; { i1 - переменная типа Integer} const StrNew: PChar = 'NewConst'; const PFunc: Pointer = @MyFunc;

    Объявление объектов данных

    Перед использованием в программе любой объект данных должен быть объявлен. Однако некоторые языки допускают неявное объявление. Так, в языке FORTRAN компилятор определяет тип используемой, но предварительно не объявленной переменной по первому символу имени, а в языке Perl неявное объявление переменной происходит при присваивании ей начального значения. Некоторые языки выполняют неявное объявление переменных, используемых в качестве счетчиков циклов.
    Оператор объявления сообщает компилятору информацию об идентификаторах и типах данных, назначаемых объектам данных, и о предполагаемом времени жизни этих объектов (глобальная или локальная переменная, переменная - член класса, статическая переменная и т.п.).
    При объявлении объекта данных в зависимости от типа этого объекта и языка программирования возможно выделение памяти под этот объект при объявлении или при последующем создании этого объекта.
    В языке C++ для объявления новых имен в текущей области видимости предназначаются операторы объявления.
    Например: int i, j; float m, n;
    Оператор объявления в языке C++ может указываться в любом допустимом месте программы.
    В языке C++ каждый оператор объявления завершается символом конца оператора (точка с запятой). В операторе объявления может объявляться несколько объектов данных одного типа, перечисляемых через запятую. Любой оператор объявления начинается с ключевого слова или идентификатора, указывающего тип объявляемого объекта.
    Объявляемыми объектами данных могут быть названия типов и имена объектов.
    Объявление определяет имя внутри области видимости. Имя, объявляемое внутри блока, класса, функции или пространства имен, является локальным. Блок в языке C++ заключается в фигурные скобки. Если вне блока существуют глобальные имена, обозначаемые теми же идентификаторами, то они становятся скрыты внутри блока и к ним следует обращаться, используя оператор разрешения области видимости ::.
    Например:
    int i1; // Объявление глобальной // переменной void metod1() { int i1; // Объявление локальной // переменной i1=22; // Доступ к локальной // переменной метода ::i1=44; // Доступ к глобальной // переменной { int i1; // Объявление локальной // переменной i1=33; // Доступ к локальной // переменной блока } i1=44; // Доступ к глобальной // переменной }

    В языке C++ объявления применяются для создания нового имени, используемого в приложении (имя может указывать не только объект данных). Объявления позволяют:

  • специфицировать класс памяти, тип и область действия объекта;
  • инициализировать объект начальным значением;
  • назначать имена константе (при объявлении перечислимого типа);
  • объявлять новый тип (class, struct и union);
  • определять синоним существующего типа (typedef);
  • специфицировать шаблон классов или функций (template);
  • специфицировать пространство имен (namespace);
  • специфицировать класс памяти, тип и область действия подпрограммы.


  • Отметим, что термин объявление означает только указание, каким образом объявляемое имя будет интерпретироваться компилятором.

    В языке C++ при каждом объявлении локального объекта под него выделяется память.

    Например:

    // Объявление и инициализация // локального объекта в цикле

    do { char char1 = _getch(); if( char1 == NULL ) continue; return (char1); } while( 1 );

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

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

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

    Например:

    boolean b1=true; // Оператор присваивания // задается символом = char c1='N'; int int1=123;

    Имена могут иметь следующие элементы языка Java:

  • пакет, определяемый оператором package;
  • тип, вводимый определением класса или интерфейса;
  • поле, являющееся переменной типа класса или типа интерфейса;
  • группа методов типа класса или типа интерфейса;
  • переменная, являющаяся формальным параметром метода;
  • переменная, являющаяся локальной переменной блока;
  • метка оператора.


  • Если имя или выражение означает переменную или значение простого типа, тогда тип этой переменной или значения называется типом имени или выражения.

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

    Например:

    var ch1: Char; {Оператор объявления в языке Object Pascal} begin ch1 := Chr(65); { Оператор присваивания задается символами :=} end;

    Переменные и константы

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

    Представление целых и вещественных типов данных

    Представление целочисленных и вещественных значений в памяти компьютера в большинстве случаев реализуется аппаратным способом с учетом возможностей конкретного процессора. Также аппаратно реализуется примитивный набор операций над этими значениями. Применение операций, реализуемых аппаратно, значительно более эффективно, чем использование программно реализуемых операций. Поэтому компиляторы по возможности формируют код, в котором применяется аппаратная реализация примитивных операций (таких, как сложение, вычитание, умножение и деление).
    Целочисленное значение типа integer, записанное как "signed 32-bit", может иметь в памяти компьютера следующее представление:
    Представление целых и вещественных типов данных
    Рис. 6.1.  Битовая структура типа integer
    Целочисленное значение типа shortint, записанное как " signed 8-bit ", может иметь в памяти компьютера следующее представление:
    Представление целых и вещественных типов данных
    Рис. 6.2.  Битовая структура типа shortint
    Максимально допустимое значение, которое можно записать в 7 бит - это восьмеричное число 177, которое в десятичном исчислении равно 127 (1778=1*82+7*81+7*80=12710).
    Таким образом, диапазон допустимых значений для каждого целочисленного типа данных определяется как стандартом языка, так и возможностями аппаратуры.
    В некоторых языках программирования представление целочисленного значения включает еще и хранение дескриптора этого значения. При этом дескриптор может храниться как в одной ячейке со значением, так и в различных ячейках. В первом случае наличие дескриптора значительно уменьшает диапазон допустимых значений, а также, как правило, замедляет процесс выполнения арифметических операций (операции над частью ячейки памяти не поддерживаются аппаратно).
    При хранении дескриптора и значения в разных ячейках (этот способ представления используется для языка LISP) одновременно с дескриптором хранится и указатель физического расположения значения.
    Вещественные типы аппаратно могут иметь два представления: вещественные числа с фиксированной точкой и вещественные числа с плавающей точкой. Как правило, по умолчанию компиляторы преобразуют вещественные значения в экспоненциальный формат (формат с плавающей точкой), если синтаксис языка явно не указывает применение формата с фиксированной точкой.
    Вещественное значение с плавающей точкой может иметь в памяти компьютера следующее представление:
    Представление целых и вещественных типов данных
    Рис. 6.3.  Битовая структура типа float
    Для представления вещественных чисел с плавающей точкой и вещественных чисел двойной точности с плавающей точкой стандартом IEEE 754 определены 32- и 64-битовые представления соответственно.
    В разряды мантиссы записываются значащие цифры, а в разряды экспоненты заносится показатель степени. Положительные значения содержат в знаковом бите числа - 0, а отрицательные значения - 1.
    При обозначении чисел с плавающей точкой приняты следующие соглашения: знаковый разряд обозначается буквой s, экспонента - e, а мантисса - m.
    В языке Java значения с плавающей точкой могут объявляться следующими базовыми типами:
  • float диапазон значений от +3.40282347E+28 до +1.40239846E-45 (32 бита)
  • double диапазон значений от +1.79769313486231579E+308 до +4.9406545841246544E-324 (64 бита).

  • Полной ненулевой формой значения типа float является форма s·m·2e, где s это +1 или -1 (знаковый бит числа), m является положительным значением, меньшим, чем 224 (мантисса), и e является целым в пределах от -149 до 104 включительно (экспонента).
    Полной ненулевой формой значения типа double является форма s·m·2e, где s это +1 или -1, m является положительным значением, меньшим, чем 253, и e является целым в пределах от -1045 до 1000 включительно.
    Положительным нулевым значением и отрицательным нулевым значением являются 0.0 и -0.0 (0.0 == -0.0 дает в результате true), но некоторые операторы различают эти "эквивалентные" значения, например, 1.0/0.0 равно положительной бесконечности, а 1.01/-0.0 - отрицательной бесконечности.
    В языке Java приняты следующие правила приведения вещественных типов:
  • любые значения любого типа с плавающей точкой могут быть приведены к любому другому значению числового типа;
  • любые значения любого типа с плавающей точкой могут быть приведены к значению типа char и наоборот;
  • приведение невозможно между значениями типа boolean и значениями с плавающей точкой.

  • Если оба операнда имеют тип float, или один имеет тип float, а другой - целый тип, то результат будет иметь тип float.
    Если же хотя бы один из операндов имеет тип double (устанавливаемый по умолчанию), то другой операнд также приводится к типу double и результат будет иметь тип double.
    Операции со значениями с плавающей точкой не выдают исключений.
    При вычислениях значений с плавающей точкой следует учитывать правила округления. Так например, для значений с плавающей точкой выражение1.0*10 не равно значению 10. Это иллюстрирует следующий пример на языке Java:
    public class MyFloatSumma { public static void main(String[] args) { float f1 = (float) 1.0; // Число с плавающей точкой float fSum = 0; // Переменная для записи результата final static float myDeltaFloat = (float) 0.00001; // Дельта для "усечения" // мусора мантиссы
    // Способ вычисления - простое // суммирование и сравнение for (byte i=0; i<10; i++) fSum = fSum + (float) 0.1; // Цикл от 0 до 10
    if (f1 == fSum) // Сравнение (float) 1.0 и // полученной суммы System.out.println("Числа равны"); else System.out.println("Числа различны"); // Правильный способ вычисления - // с "усечением" мусора мантиссы fSum = 0; for (byte i=0; i<10; i++) fSum = fSum + (float) 0.1; if (Math.abs(fSum - f2) < myDeltaFloat) System.out. println("Числа одинаковы"); else System.out. println("Числа различны"); } }
    Представление целых и вещественных типов данных

    Преобразование типов в языке C++

    Язык C++ позволяет выполнять преобразование значения одного типа в значение другого типа. Преобразование типа может быть явным и неявным. Явное преобразование называется приведением типов.
    Для явного приведения типов можно использовать две формы записи:

  • без указания дополнительной информации для преобразования типа (перед преобразуемой переменной в скобках указывается имя типа, к которому она приводится).
    Например:
    std::cout <<"strlen="<<(long)strlen(pArr1);

  • с указанием дополнительной информации для преобразования типа (используются операторы static_cast, dynamic_cast, reinterpret_cast и const_cast).
    Например:
    std::cout <<"strlen="<( strlen(pArr2));

  • Вторая форма явного преобразования типов более предпочтительна, поскольку несет в себе дополнительную информацию, позволяющую сократить число возможных ошибок.
    Дополнительная информация о приводимом типе может быть указана следующими операторами:
  • static_cast - выполняет преобразование родственных типов;
  • const_cast - выполняет приведение константных выражений;
  • dynamic_cast - используется для динамического преобразования типа, реализуемого на этапе выполнения;
  • reinterpret_cast - выполняет преобразование не связанных между собой типов.

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

    Типы данных языка C++

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

  • Базовые типы языка C++ можно подразделить на две группы: целочисленные и вещественные. Существует еще ключевое слово void, которое используется для описания типа подпрограмм, не имеющих возвращаемого значения, или при указании параметров подпрограмм неизвестного типа.

    char
    signed char

    Символьный тип. Диапазон значений от -128 до 127.
    Содержит один символ или строку символов. Каждый символ представляется одним байтом. Компилятор различает как отдельные следующие типы: char, signed char и unsigned char.
    unsigned char
    Символьный тип. Диапазон значений от 0 до 255.
    Каждый символ представляется одним байтом (значение в диапазоне от 0 до 255).

    short
    signed short

    Целый тип. Диапазон значений от -32768 до 32767.
    Сокращенное обозначение типа short int. Длина этого типа вне зависимости от используемого компилятора всегда больше или равна длине значения типа char и меньше или равна длине значения типа int.
    unsigned shortБеззнаковый целый тип. Диапазон значений от 0 до 65535.

    int
    signed int

    Целый тип. Диапазон значений от -2147483648 до 2147483647.
    Длина этого типа вне зависимости от используемого компилятора всегда больше или равна длине значения типа short int.
    В общем случае размер типа int языка C++ зависит от конкретной реализации.
    unsigned intБеззнаковый целый тип. Диапазон значений от 0 до 4294967295.
    __intnЦелый тип, размер в битах которого определяется значением n, и может быть равным 8, 16, 32 или 64 битам.

    long
    signed long

    Целый тип. Диапазон значений от -2147483648 до 2147483647.
    Сокращенное обозначение типа long int.
    unsigned longБеззнаковый целый тип. Диапазон значений от 0 до 4294967259
    floatТип данных с плавающей точкой. Диапазон значений от 3.4Е-38 до 3.4Е+38.
    double
    Тип данных с плавающей точкой двойной точности. Диапазон значений от 1.7Е-308 до 1.7Е+308.
    Длина типа double вне зависимости от используемого компилятора всегда больше или равна длине типа float и короче или равна длине типа long double.
    long double
    Тип данных с плавающей точкой двойной точности, длина которого равна длине значений типа double.
    Типы double и long double имеют одинаковое представление, но компилятор трактует их как различные типы.
    <
    Размер памяти, выделяемой под каждый тип данных языка C\C++, в некотором смысле зависит от используемой платформы и компилятора. Однако все компиляторы гарантируют, что для типа short памяти всегда выделяется меньше или столько же, сколько и для типа int, а тип long всегда "длиннее" или равен типу int.

    Символьные типы char и unsigned char представляют значение символа, реализуемое одним байтом. Для использования символов в кодировке Unicode язык C++ предоставляет тип wchar_t, в котором под каждый символ отводятся два байта.

    Ключевое слово typedef языка C++ позволяет объявить новое имя существующего типа.

    Например:

    typedef int my_integer; my_integer i1=0;

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

    Символьным литералом или символьной константой называется символ, заключенный в одинарные кавычки. Целые литералы представляют целочисленные константы в десятичном, восьмеричном или шестнадцатеричном виде.

    Восьмеричные литералы начинаются с символа 0, а шестнадцатеричные - с символов 0x.

    После литерала может быть указан суффикс, определяющий его тип: U - unsigned int, L - long int.

    Например:

    00 // Восьмеричное значение, равное 0 oxffff // Шестнадцатеричное значение, // равное 65535 10L // Значение типа long int

    При записи шестнадцатеричных литералов каждый знак может принимать значение от 0 до 15. Для записи значений от 10 до 15 принято использовать следующие символы: a - 10, b - 11, c - 12, d - 13, e - 14 и f - 15.

    Литералы с плавающей точкой могут записываться в двух формах: вещественной и экспоненциальной.

    Например:

    1.53 32.24e-12 // Экспоненциальная форма записи литерала

    Литералы с плавающей точкой могут использоваться для инициализации значений переменных вещественного типа (float, double или long double).

    Типы данных языка Java

    Java - это язык со строгой типизацией. Это означает, что типы данных должны быть определены уже на этапе компиляции.
    Все типы данных в Java можно подразделить на две группы:
  • простые типы;
  • ссылочные типы.

  • Язык Java позволяет использовать следующие простые типы:
  • числовые типы
    целые типы:
  • byte (8-битовое значение) диапазон значений от -128 до 127
  • short (16-битовое значение) диапазон значений от -32768 до 32767.
  • int (32-битовое значение) диапазон значений от -2147483648 до 2147483647
  • long (64-битовое значение) диапазон значений от -9223372036854775808 до 9223372036854775807

  • типы значений с плавающей точкой:
  • float (32-битовое значение)
  • double (64- битовое значение)


  • символьный тип
  • char (16-битовое значение Unicode)


  • логический тип
  • boolean (значение true или false)


  • Например:
    // Объявление переменных boolean b1=true; float fN1=74.3F; float fN2=(float)(fN1+2); double dN1=14573.74; double dN2= 81.2E-2;
    Значение одного целого типа может быть приведено к значению другого целого типа.
    Приведение целых типов к логическому и обратно выполнять нельзя.
    Язык Java предусматривает для целочисленных значений следующие операторы:
  • операторы сравнения
  • = равно
  • != не равно

  • операторы отношения
  • < меньше
  • <= меньше или равно
  • > больше
  • >= больше или равно

  • унарные операторы
  • + положительное значение
  • - отрицательное значение

  • бинарные операторы
  • + и += сложение (x=x+y эквивалентно записи x+=y)
  • - и -= вычитание (x=x-y эквивалентно записи x-=y)
  • * и *= умножение (x=x*y эквивалентно записи x*=y)
  • / и /= деление (x=x/y эквивалентно записи x/=y)
  • % и %= остаток от деления

  • префиксный и постфиксный оператор приращения и декремента
  • ++ приращение (увеличение значения на 1 до вычисления выражения (++x) или после (x++))
  • -- декремент

  • операторы сдвига
  • << сдвиг влево
  • >> сдвиг вправо с распространением знака
  • >>> сдвиг вправо без учета знака (слева происходит заполнение нулями)

  • унарный логический оператор
  • ~ отрицание (побитовое дополнение)

  • бинарные логические операторы
  • & логическое И (AND)
  • | логическое ИЛИ (OR)
  • ^ логическое исключающее ИЛИ (XOR)




  • Если оба операнда имеют целочисленный тип, то операция рассматривается как целочисленная. Если один из операндов имеет тип long, то операция выполняется с использованием 64-битового представления: при этом любой другой операнд будет расширен до типа long и результат будет также иметь тип long. В противном случае операции выполняются, используя 32-битовое представление (любой операнд, не являющийся int, первоначально расширяется до типа int) и результат будет иметь тип int.

    Логические значения представляются одним битом и обозначаются константами true и false

    В языке Java нельзя прямо выполнить приведение типа int к типу boolean, но можно конвертировать значение int, используя следующий синтаксис языка: int x != 0, где любое не нулевое значение x даст в результате true, а нулевое значение даст false. Для преобразования значения типа boolean в целое следует выполнить условный оператор: bool x ? 1:0.

    Для логических значений в языке Java предусмотрены следующие операторы:

  • == и !=
  • !, &, |, и ^
  • && и ||.


  • Типы данных языка Object Pascal

    Все переменные и константы, используемые в программе, всегда принадлежат какому-либо типу. Вызов функции также возвращает значение определенного типа.
    Типы данных языка Object Pascal можно разбить на следующие группы:
  • базовые типы данных:
  • целочисленный тип;
  • действительный тип;
  • логический тип;
  • символьный тип;
  • строковый тип;

  • производные типы данных;
  • простые типы данных:
  • порядковый тип;
  • перечислимый тип;

  • структурированные типы данных:
  • множества;
  • массивы;
  • записи;
  • файлы;
  • объектный тип (тип класса);
  • тип ссылки на класс;

  • указатели;
  • процедурный тип данных.

  • В язык Object Pascal включены следующие базовые типы данных:

  • Целочисленные типы
    ТипДиапазон значенийФормат
    Integer-2147483648..2147483647signed 32-bit
    Cardinal0..4294967295unsigned 32-bit
    Shortint-128..127signed 8-bit
    Smallint-32768..32767signed 16-bit
    Longint-2147483648..2147483647signed 32-bit
    Int64-263..263-1signed 64-bit
    Byte0..255unsigned 8-bit
    Word0..65535unsigned 16-bit
    Longword0..4294967295unsigned 32-bit


  • Действительные типы
    ТипДиапазон значенийРазмер в байтах
    Real5.0 * 10-324 .. 1.7 * 103088
    Real482.9 * 10-39 .. 1.7 * 10386
    Single1.5 * 10-45 .. 3.4 * 10384
    Double5.0 * 10-324 .. 1.7 * 103088
    Extended3.6 * 10-4951 .. 1.1 * 10493210
    Comp-263+1 .. 263 -18
    Currency-922337203685477.5808.. 922337203685477.58078

    Для указания значения действительного типа можно использовать экспоненциальный формат (например, значение 1.3Е-5 эквивалентно 1.3*10-5).

  • Логические типы
    ТипДиапазон значенийРазмер в байтах
    BooleanTrue или False1
    ByteBoolTrue или False1
    WordBoolTrue или False2
    LongBoolTrue или False4

  • Символьные типы
    ТипДиапазон значенийРазмер в байтах
    CharANSI-символ 1
    AnsiCharANSI-символ 1
    WideCharUnicode-символ 2

  • Строковые типы
    ТипМаксимальная длинаРазмер в байтах
    stringОпределяется директивой компилятора $H
    ShortString255 символовОт 2 до 256 байт
    AnsiString (длинная строка)~231 символовОт 4 байт до 2 Гбайт
    WideString (Символы Unicode)~230 символовОт 4 байт до 2 Гбайт


  • Для строковых переменных выполняются следующие правила:

  • строки могут быть постоянной или переменной длины: при объявлении строки можно указать только идентификатор или идентификатор и в квадратных скобках длину строки;
  • значение строки указывается в одинарных кавычках или как последовательность ASCII-символов, перед каждым из которых ставится знак #;
  • доступ к символу строки можно выполнять по индексу, указываемому в квадратных скобках (например, MyString[7] := 'n';).


  • Например:

    var S1: string; {Объявление строковой переменной произвольной длины} S2: string[2]; {Объявление строковой переменной длиной 2 символа}

    Строки типа AnsiString также называют длинными строками (long string), представляющими динамически размещаемые строки, длина которых ограничена только доступной памятью. Такие строки используют 1-байтовое представление ANSI-символов.

    Реально переменная типа AnsiString является указателем, состоящим из 4 байт. Если строка пустая (ее длина равна 0), то указатель равен nil и для хранения строки никакой памяти не выделяется. Если строка не является пустой, то данная переменная указывает на динамически размещаемый блок памяти, содержащий значение строки, на 32-битовое значение длины строки и на 32 битовое значение счетчика ссылок на строку.

    Несколько идентификаторов строк могут ссылаться на одну строку. При этом им не будет выделяться дополнительная память, а только будет выполняться увеличение счетчика ссылок.

    Типы данных

    Тип данных назначается объекту данных при его объявлении и определяет: значения, которые может принимать объект данного типа; операции, которые используются для манипуляции над объектами заданного типа.
    Современные языки программирования, как правило, могут иметь набор простых типов, являющихся встроенными в данный язык программирования, и средства для создания производных типов.
    Объектно-ориентированные языки программирования позволяют определять типы класса.
    Реализация простых типов данных заключается в способе представления значений данного типа в компьютере и в наборе операций, поддерживаемых для данного типа.

    Введение в программирование

    Элементы массива

    Доступ к элементам массива может выполняться:
  • по указателю на массив и индексу элемента, задаваемого в квадратных скобках: первый элемент массива имеет индекс 0;
  • по указателю на элемент массива.

  • Для получения адреса элемента массива применяется оператор &.
    Имя массива является адресом массива и эквивалентно следующему выражению: &имя_массива[0].
    Для определения размерности массива в байтах можно использовать функцию sizeof(имя_массива).
    Например:
    arrayOfInteger[0]=1; // Присваивание значения // первому элементу массива iInt1=arrayOfInteger[1]=13; // Групповое присваивание iInt2=&arrayOfInteger[4]; // Получение адреса пятого // элемента массива

    Константные указатели

    Значение указателя на константу можно изменять, а значение константного указателя является константой и не подлежит изменению.
    Например:
    char str1[]="123"; const char* pstr1= str1; // pstr1 можно изменять, // а *pstr1 - нельзя.
    Задание ключевого слова const перед объявлением указателя создает этот указатель как указатель на константу (при этом само значение, доступное не через данный указатель, остается изменяемым).
    Для того чтобы создать константный указатель, вместо оператора * используется *const.
    Например:
    const char *const pstr1= str1;

    Объявление массивов

    Массив переменных или объектов состоит из определенного числа однотипных данных, называемых элементами массива. Все элементы массива индексируются последовательно, начиная с нуля.
    Размещение элементов массива в памяти выполняется последовательно.
    Количество элементов в массиве определяет размер массива и является константным выражением. Для создания динамических массивов стандартная библиотека C++ предусматривает тип vector.
    Имя массива определяет адрес первого элемента массива.
    Имя массива в отличие от имени вектора нельзя указывать в левой части оператора присваивания.
    Объявление массива может иметь следующее формальное описание:
    // Объявление одномерного массива тип имя_массива[размерность_N]; // Объявление одномерного массива с // одновременной инициализацией тип имя_массива[размерность_N]= {значение0, значение1, ..., значение_N-1}; // Объявление безразмерного массива с // одновременной инициализацией: // размерность определяется количеством // значений, указанных в списке инициализации тип имя_массива[]={значение0, значение1, ..., значение_N-1}; // Объявление многомерного массива тип имя_массива[размерность_1N]... [размерность_MN]; // Объявление многомерного массива с // одновременной инициализацией тип имя_массива [размерность_N]... [размерность_M] = { {значение0, значение1, ..., значение_M-1}, ... {значение0N, значение1N, ..., значение_NM-1}};
    Размерность массива может:
  • указываться любым константным выражением целого типа;
  • автоматически определяться компилятором по списку значений инициализации массива (если размерность не указана явно).

  • Например:
    int arrayOfInteger[17]; // Массив из 17 переменных типа int char arrayOfChar_3[3]={'L','M','N'}; // Объявление и инициализация // символьного массива char arrayOfChar_0[]={"Array of char. \n"}; int arrayOfInteger_6[2][3]= { {1,2,3}, {11,12,13}}; // Объявление и инициализация // двумерного массива
    Если ни размерность массива, ни список значений инициализации не указаны, то будет создан массив нулевой длины.

    Объявление многомерных массивов выполняется по следующим правилам:

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


  • Инициализацию массива можно выполнить одним из следующих способов:

  • указать во время объявления массива в фигурных скобках значения инициализации (начиная с нулевого элемента и первого столбца);
  • присвоить значение элементам массива во время выполнения программы;
  • объявить массив как глобальный или статический, инициализируемый по умолчанию (для числовых значений выполняется инициализация нулями, а для указателей - значением null). Глобальный массив объявляется вне всех функций, а статический массив объявляется с модификатором static.


  • Если количество значений инициализации больше, чем объявленная размерность массива, то компилятор Visual C++ инициирует ошибку.

    Если количество значений инициализации меньше, чем объявленная размерность массива, то оставшиеся значения автоматически инициализируются нулями.

    Преобразование типа указателя

    Преобразование типа указателя происходит при различных операциях, таких как вызов процедуры, присваивание, инициализация и т.п.
    Указатель типа void может быть преобразован к указателю любого другого типа только явным приведением типа. Но указатель любого типа может быть неявно преобразован к указателю типа void.
    Это применяется для передачи параметров функции, если тип формального параметра не очевиден (он может быть указателем типа int * или типа float *). В этом случае в прототипе функции вместо явного задания типа записывается тип void.
    Например:
    Fx(void *px); // Прототип функции Fx(pi); // Вызов функции для int * pi Fx(pf); // Вызов функции для float * pf
    В теле функции для работы с указателем следует использовать явное преобразование типа.
    Например: (int *)px.

    Производные типы

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

  • Составные производные типы. В группу составных производных типов входят:
  • классы
  • структуры
  • объединения



  • Размещение массива в памяти

    При создании массива память под все его элементы выделяется последовательно для каждого элемента в зависимости от типа массива. Для многомерных массивов в первую очередь изменяются значения самого правого индекса.
    Например, для массива char aCh[2][4] будет выделено восемь байтов памяти, в которых в следующем порядке будут размещены элементы массива:
    элементN байта
    aCh[0][0]aCh[0][1]aCh[0][2]aCh[0][3]aCh[1][0]aCh[1][1]aCh[1][2]aCh[1][3]
    12345678

    Двухмерные массивы можно рассматривать как матрицу, в которой первый индекс определяет строку, а второй индекс - столбец. Порядок расположения элементов матрицы в памяти - по строкам.
    При размещении трехмерного массива char aCh[3][2][5] память под элементы этого массива будет выделяться последовательно в соответствии со следующими значениями индексов:
    Размещение массива в памяти
    Рис. 7.1. 
    Общий объем выделяемой под массив памяти определяется как произведение всех размерностей массива (общее число элементов), умноженное на длину типа данных массива.

    Символьные массивы и строки

    Синтаксис языка не имеет простого строкового типа (стандартная библиотека содержит тип string, но переменные данного типа не являются массивами символов). Поэтому для работы со строками удобно использовать массивы символов. Объявить массив символов - строку можно двумя способами:
  • указать посимвольно каждый элемент массива, включая символ конца строки;
  • указать в двойных кавычках при инициализации массива значение строки (символ конца строки будет добавлен автоматически).

  • Символом конца строки служит null-символ \0. При подсчете числа символов в строке учитывается общее число символов плюс символ конца строки.
    Например:
    char arrayOfChar[6]; arrayOfChar[0]='A'; // Доступ через указатель // на массив и индекс char * ph = arrayOfChar; // Создание указателя на элемент массива ph++; // Переход к следующему элементу массива
    Префиксный оператор * называется оператором разыменования. Если ph указывает на элемент массива, то *ph является значением этого элемента.
    Любое выражение, имеющее тип массива, может быть преобразовано к указателю того же типа: результатом будет указатель на первый элемент массива.
    Например:
    char cStr[_MAX_PATH]; // Массив типа char char *pStr = cStr; // Указатель на массив: // эквивалентно выражению &cStr[0]

    Ссылки

    Ссылка вводит для доступа к переменной второе имя и является константным указателем на объект. Значение переменной-ссылки изменить нельзя. При объявлении ссылки перед именем переменной ставится символ &. Ссылка при объявлении всегда должна быть проинициализирована.
    Например:
    int iV=12; int &sV=iV; // sV - ссылка cout<< sV; // sV равно 12 sV=22; // значение iV // стало равно 22 sV++; // sV и iV стало равно 23 int *pV= &sV; // указатель на sV и iV

    Типы, определяемые в пространствах имен

    Пространство имен позволяет именовать группу переменных и методов.
    Создание пространства имен указывается ключевым словом namespace.
    Пример:
    namespace S // Пространство имен S { int i; } void main() { S::i++; // Обращение к переменной // i из пространства имен S }
    В языке C++ объявляемые пространства имен могут быть иерархически вложены друг в друга.
    Например:
    namespace Outer { int iOuter1= 111; int func(int j); namespace Inner { int iInner1 = 222; } }
    Для традиционных приложений можно использовать стандартную библиотеку C++, которая определяет дополнительный набор типов. Пространство имен стандартной библиотеки обозначается идентификатором std.
    Для того чтобы иметь возможность обращаться к переменным или методам из пространства имен, можно использовать один из следующих способов:

  • имя соответствующей переменной или метода должно быть квалифицировано названием пространства имен (пространство имен указывается перед именем через два символа двоеточия). Например:
    std::string s="Это строка";

  • имя библиотеки должно быть установлено как доступное оператором using. Например:
    using namespace std; // ... string s1="Строка s1";

  • Оператор using можно указывать как до метода main, так и внутри метода main (в этом случае переменные и методы пространства имен будут доступны без квалификации их имени сразу после выполнения оператора using).
    Для управляемых расширений используются библиотеки среды NET Framework, реализованные как пространства имен. Пространство имен System предоставляет большой набор типов, реализованных как классы или структуры. Типы, определяемые в пространствах имен

    Указатели на массивы

    И указатель, и массив содержат адрес. Поэтому указателю может быть присвоен адрес первого элемента массива или имя массива. Но адресу массива нельзя присвоить значение указателя.
    Например:
    float fArray[3]; // Массив float* pArray; pArray=fArray; // Эквивалентно оператору // pArray=&fArray[0]; pArray++; // Указывает на второй // элемент массива float* pArray2; pArray2=&fArray[1]; // Указывает на второй //элемент массива

    Указатели на переменные

    Указатель на переменную содержит адрес памяти расположения этой переменной.
    Объявление указателя имеет следующее формальное описание:
    тип_переменной *имя_переменной_адреса;
    Инициализация указателя выполняется следующим образом:
    тип_переменной имя_переменной_содержания; имя_переменной_адреса = &имя_переменной_содержания;
    Объявление указателя может быть выполнено с одновременной инициализацией:
    тип_переменной *имя_переменной_адреса = &имя_переменной_содержания;
    Доступ к значению переменной по указателю имеет следующее формальное описание:
    имя_переменной_содержания1=*имя_переменной_адреса;
    При работе с указателями действуют следующие правила:
  • при объявлении переменной-указателя перед именем переменной указывается операция *;
  • если одним оператором объявляется несколько переменных-указателей, то перед каждой такой переменной следует указывать операцию *;
  • после объявления указателя его следует инициализировать адресом значения того же типа, что и тип указателя;
  • для получения адреса переменной перед ее именем указывается операция взятия адреса &;
  • для получения значения переменной по указателю на нее перед указателем ставится операция разыменования * (называемая иногда операцией взятия значения);
  • указатель строки содержит адрес первого символа строки;
  • при увеличении указателя на единицу значение, содержащееся в переменной-указателе, увеличивается на число байт, которое отведено под переменную данного типа.

  • Операцию разыменования & нельзя использовать:
  • для регистровых переменных (register r1; pReg=&r1;);
  • с константами (pAdr1=&444;);
  • с арифметическими выражениями (int i=1234; pAdr1=&(i+3);).

  • Например:
    int iVar; int* pInt; // Указатель pInt=&iVar; // Эквивалентно оператору // int *pInt=&iVar; *pInt=20; // Эквивалентно оператору // iVar=20; char* pStr="The string"; iVar=strlen(pStr); // Определение длины строки
    Указателю может быть присвоено значение другого указателя: в этом случае следует использовать операцию *. Компилятор Visual C++ отслеживает некорректные присваивания - указателю значения или наоборот, и выдает предупреждение о различных уровнях адресации.

    На следующей схеме иллюстрируется соотношение указателя и значения.

    ПеременныеУказателиОбъявление и инициализацияchar Achar Bchar*pAchar*pB2000200130003020
    Адреса ячеек памяти
    Операции:Содержание ячеек:
    A='w';w
    pA=&A; //адрес переменной А2000
    B=*pA; //значение переменной Аw
    *pA='я'; //изменение значенияя
    pB=pA; //адрес переменной А2000
    pB=&A; //адрес переменной А2000
    Операции инкремента ++ и декремента -- указателя можно выполнять как после операции присвоения (*pV++=22;), так и до нее (*++pV=22;). В последнем случае сначала будет увеличено значение указателя, а затем выполнен оператор присваивания.

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

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

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

    Указатели на указатели

    Объявление указателя на указатель имеет следующее формальное описание:
    тип **имя_указателя_на_указатель;
    При объявлении указателя на указатели уровнем вложенности указателей служит число звездочек перед именем переменной.
    Для получения значения по указателю на указатели перед именем указателя надо записать количество звездочек, равное уровню вложенности указателя.
    Например:
    int iV, jV; int* pV=&iV; // pV - это адрес, //а *pV - значение int** ppV=&pV; int*** pppV=&ppV; iV=77; // Эквивалентно **ppV=77; jV=*pV; // Эквивалентно jV=**ppV; // или jV=***pppV;

    Введение в программирование

    Доступ к элементам структуры

    Элементы структуры могут иметь модификаторы доступа: public, private и protected. По умолчанию все элементы структуры объявляются как общедоступные (public). Забегая вперед, следует сказать, что все члены класса по умолчанию объявляются как защищенные (private).
    Для обращения к отдельным элементам структуры используются операторы: . и ->.
    Доступ к элементам структуры может иметь следующее формальное описание:
    переменная_структурного_типа.элемент_структуры=значение; имя_структурного_типа *указатель_структуры= & переменная_структурного_типа; указатель_структуры->элемент_структуры=значение;
    Например:
    struct structA { char c1; char s1[4]; float f1;} aS1, // aS1 - переменная структурного типа *prtaS1=&aS1; // prtaS1 - указатель на структуру aS1 struct structB { struct structA aS2; // Вложенная структура } bS1,*prtbS1=&bS1; aS1.c1= 'Е'; // Доступ к элементу c1 структуры aS1 prtaS1->c1= 'Е'; // Доступ к элементу c1 через // указатель prtaS1 (*prtaS1).c1= 'Е'; // Доступ к элементу c1 (prtbS1->aS2).c1='Е'; // Доступ к элементу вложенной структуры
    Доступ к элементу массива структурного типа имеет следующий формальный синтаксис:
    имя_массива[индекс_элемента_массива].элемент_структуры
    При использовании указателей на массив структур следует сначала присвоить указателю адрес первого элемента массива, а затем реализовывать доступ к элементам массива, изменяя этот указатель адреса.
    Например:
    struct structA { int i; char c;} sA[4], *psA; psA=&sA[0]; … cout<i; // Доступ к первому элементу массива // структур // Переход ко второму элементу массива psA++; // Эквивалентно записи: psA=&sA[1]; cout<i;

    Объединения

    Объединение позволяет размещать в одном месте памяти данные, доступ к которым реализуется через переменные разных типов.
    Использование объединений значительно экономит память, выделяемую под объекты.
    При создании переменной типа объединение память под все элементы объединения выделяется исходя из размера наибольшего его элемента. В каждый отдельный момент времени объединение используется для доступа только к одному элементу данных, входящих в объединение.
    Так, компилятор Visual C++ выделит 4 байта под следующее объединение:
    union unionA { char ch1; float f1;} a1; Элементы объединенияКоличество занимаемых байтов
    char ch1
    1
    float f1
    1234

    Объединения, как и структуры, могут содержать битовые поля.
    Инициализировать объединение при его объявлении можно только заданием значения первого элемента объединения.
    Например:
    union unionA { char ch1; float f1;} a1={ 'M' };
    Доступ к элементам объединения, аналогично доступу к элементам структур, выполняется с помощью операторов . и ->.
    Например:
    union TypeNum { int i; long l; float f; }; union TypeNum vNum = { 1 }; // Инициализация первого элемента объединения i = 1 cout<< vNum.i; vNum.f = 4.13; cout<< vNum.f;
    Элементы объединения не могут иметь модификаторов доступа и всегда реализуются как общедоступные (public).

    Объявление структуры

    Структуры языка C++ представляют поименованную совокупность компонентов, называемых полями, или элементами структуры. Элементом структуры может быть:
  • переменная любого допустимого типа;
  • битовое поле;
  • функция.

  • Объявление структуры имеет следующее формальное описание:
    struct [имя_структуры] { тип_элемента_структуры имя_ элемента1; тип_элемента_структуры имя_ элемента2; ... тип_элемента_структуры имя_ элементаN; } [список_объявляемых_переменных];
    Объявление структуры с битовыми полями имеет следующее формальное описание:
    struct [имя_структуры] { тип_элемента_структуры [имя_ элемента1] : число_бит; тип_элемента_структуры [имя_ элемента2] : число_бит; ... тип_элемента_структуры [имя_ элементаN] : число_бит; } [список_объявляемых_переменных];
    Возможно неполное объявление структуры, имеющее следующее формальное описание:
    struct имя_структуры;
    При отсутствии имени объявляемой структуры создается анонимная структура. При создании анонимной структуры обычно указывается список объявляемых переменных.
    Список объявляемых переменных типа данной структуры может содержать:
  • имена переменных;
  • имена массивов;
  • указатели.

  • Например: struct sA {char a[2], int i;} struA, struB[10], *struC;
    Для использования указателя на структуру ему необходимо присвоить адрес переменной типа структуры.
    Размер структуры с битовыми полями всегда кратен байту. Битовые поля можно определять для целочисленных переменных типа int, unsigned int, char и unsigned char. Одна структура одновременно может содержать и переменные, и битовые поля. Если для битового поля не задано имя элемента, то доступ к такому полю не разрешен, но количество указанных бит в структуре размещается.
    Типом элемента структуры может быть:
  • другой структурный тип (допускаются вложенные структуры);
  • указатель на данный структурный тип;
  • неполно объявленный структурный тип;
  • любой другой базовый или производный тип, не ссылающийся рекурсивно на объявляемый структурный тип.

  • Например:
    struct sA {char a[2], sA* this_struct;}; // Корректное объявление структуры struct sB; // Неполное объявление структуры struct sA {char a[2], sB* this_struct;}; // Корректное объявление структуры struct sA {char a[2], sA this_struct;}; // Ошибочное объявление
    Структура не может содержать в качестве вложенной структуры саму себя, но она может содержать элемент, являющийся указателем на объявляемую структуру.
    Например:
    struct structA { struct structA *pA; int iA; } sA; // pA указатель на структуру
    При одновременном объявлении структурного типа, объявлении переменной данного типа и ее инициализации список значений указывается в фигурных скобках в последовательности, соответствующей последовательности определения элементов структуры.
    Например:
    struct POINT // Объявление структурного // типа POINT { int x; // Объявление элементов x и y int y; } p_screen = { 50, 100 }; // Эквивалентно записи p_screen.x = 50; // и p_screen.y = 100;

    Перечисления

    Перечисление, или перечислимый тип определяет множество, состоящее из значений, указанных через запятую в фигурных скобках.
    Перечисление задает для каждого мнемонического названия в указываемом множестве свой индекс.
    Перечисление может иметь следующее формальное описание:
    enum имя_типа {список_значений} список_объявляемых_переменных; enum имя_типа список_объявляемых_переменных; enum (список_элемент=значение);
    Перечислимый тип описывает множество, состоящее из элементов-констант, иногда называемых нумераторами или именованными константами.
    Значение каждого нумератора определяется как значение типа int. По умолчанию первый нумератор определяется значением 0, второй - значением 1 и т.д. Для инициализации значений нумератора не с 0, а с другого целочисленного значения, следует присвоить это значение первому элементу списка значений перечислимого типа.
    Например:
    // Создание перечисления enum eDay{sn, mn, ts, wd, th, fr, st} day1; // переменная day1 будет принимать // значения в диапазоне от 0 до 6 day1=st; // day1 - переменная перечислимого типа int i1=sn; // i1 будет равно 0 day1= eDay(0); // eDay(0) равно значению sn enum(color1=255); // Объявление перечисления, определяющего // именованную целую константу color1 int icolor=color1; enum eDay2{sn=1, mn, ts, wd, th, fr, st} day2; // переменная day2 будет принимать // значения в диапазоне от 1 до 7
    Для перечислимого типа существует понятие диапазона значений, определяемого как диапазон целочисленных значений, которые может принимать переменная данного перечислимого типа.
    Для перечислимого типа можно создавать указатели. Перечисления

    Передача структур в качестве параметров

    Переменные структурного типа и элементы структуры можно передавать в функции в качестве параметров.
    Передача параметров может выполняться:
  • по ссылке или указателю;
  • по значению.

  • При передаче параметра по указателю передается только указатель на структуру, при передаче по значению в стек копируется все содержание структуры.
    Например:
    struct structA { int i; char c;} sA, *psA=&sA; void F1(struct structA sA); // Передача параметров по значению void F2(struct structA *psA); // Передача параметров по указателю void F3(struct structA &sA); // Передача параметров по ссылке … void F2(struct structA *psA) { psA->i =10; } // Доступ к элементу структуры
    При большой вложенности вызовов и использовании большого числа структур или их значительных размерах вызов по значению может привести к переполнению стека.
    Функция может возвращать значение структурного типа или типа указателя на структуру.
    Например:
    struct structA { int i; char с;}; struct structA Function3(void); // Функция возвращает значение // структурного типа struct structA *Function4(void); // Функция возвращает указатель // на структуру

    Выделение памяти

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

  • Рассмотрим пример выделения памяти под структуру
    struct structA { char cA; char sA[2]; float fA;};
    При создании переменной структурного типа:
    structA s1;
    будет выделено 7 байтов. Элементы структуры будут размещены в памяти в следующем порядке:
    char cAchar sA[2]float fA
    1234567

    Рассмотрим пример выделения памяти под структуру
    struct structB { int i1:2; int i2:3; int :6; unsigned int i3:4;};
    При создании переменной структурного типа:
    structB s2;
    будет выделено 2 байта. Элементы структуры будут размещены в памяти в следующем порядке:
    Выделение памяти
    Рис. 8.1. 
    Для целочисленных значений, предусматривающих наличие знакового разряда (например, int), старший левый бит из общего числа битов, выделяемых под данное битовое поле, интерпретируется как знак. Например, битовое значение 11 для поля i1 будет восприниматься как -1, а значение 11 для поля i3 - как 3.

    Введение в программирование

    Файлы

    Файл представляет собой упорядоченный набор элементов одного типа.
    Стандартные процедуры ввода и вывода используют предопределенный тип TextFile, или Text, который реализует файл как упорядоченный набор строк символов.
    Объявление типа файл и создание переменных файлового типа имеет следующее формальное описание:
    type тип_файла = file of тип; var идентификатор: file of тип_файла;
    Тип, указываемый после ключевых слов file of, может быть производным типом или базовым типом. Так, в качестве типа можно указать string[число_символов] или array[нач_инд..кон_инд] of Char.
    Объявление нетипизированного файла имеет следующее формальное описание:
    var идентификатор: file;
    Для создания переменной файлового типа следует предварительно объявить файловый тип, а затем объявить переменную созданного типа, или сразу объявить переменную, указав используемый тип как файловый.
    Например:
    type Phone = record Name: string[30]; PhoneNumber: string[20]; end; {Объявление файлового типа } PhoneList = file of Phone; var {Объявление переменной файлового типа} book1: PhoneList; {Объявление переменной с указанием типа как файлового типа} book2: file of Phone;
    Файлы

    Массивы

    В языке Object Pascal можно создавать одномерные и многомерные массивы. Все элементы массива имеют одинаковый тип.
    Одномерный массив языка Object Pascal имеет следующее формальное описание:
    Идентификатор: array [нач_индекс..кон_индекс] of тип_массива;
    Например:
    type RealArr = array[1..100] of Real; var int1: array[1..20] of Integer; int2: array[1..20] of Integer; int3, int4: array[1..10] of Integer; real1: array[1..10] of Real; begin Int1 := Int2; end.
    Массивы могут объявляться как константы.
    Например:
    type TCub = array[0..1, 0..1, 0..1] of Integer; const cub1: TCube = (((0, 1), (2, 3)), ((4, 5), (6,7))); { Элементы массива cub1 будут содержать следующие значения: cub1 [0,0,0] = 0 cub1 [0,0,1] = 1 cub1 [0,1,0] = 2 и т.д. }
    Массив символов объявляется как массив переменных типа Char. Символьный массив может быть доступен через указатель на массив типа PChar.
    Строки можно реализовывать как символьные массивы, ограниченные 0-символом (#0).
    Например:
    const TempString: array[0..8] of Char = 'Строка'#0; var P: PChar; {Указатель на строку} begin P := 'Строка'; P := @TempString; {Переменная P указывает на значение 'Строка'} end.
    Массив символов типа Char и значение типа PChar эквивалентны.
    Например:
    var MyArray: array[0..5] of Char; MyPointer: PChar; begin MyArray := 'array'; MyPointer := MyArray; MyProc(MyArray); {Эквивалентно вызову MyProc(MyPointer);} end.
    Многомерный массив имеет следующее формальное описание:
    array[диапазон_первого_индекса, ..., диапазон_n_индекса] of базовый_тип; array[диапазон] of array[диапазон] of array[диапазон] of тип;
    Так, объявление
    type MyMassiv = array[1..10] of array[1..70] of Integer;
    эквивалентно объявлению
    type MyMassiv = array[1..10, 1..70] of Integer;
    Например:
    type MyAr = array[1..10, 1..50] of Real; begin MyAr[1,49]:= 49; end.
    По принципу выделения памяти под массив массивы языка Object Pascal делятся на статические и динамические.
    Память под статический массив выделяется при его создании.
    Динамический массив не имеет фиксированного размера или длины.

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

    Создание динамического массива имеет следующее формальное описание:

    array of тип_элементов_массива;

    Например:

    {Объявление динамического массива} var MyAr: array of Integer; {Определение количества элементов в динамическом массиве:} SetLength(MyAr, 10);

    Элементы динамического массива всегда индексируются с 0. Переменная типа динамического массива является указателем, и к ней применимы операции над указателями. Для освобождения памяти, занимаемой динамическим массивом, можно присвоить значение nil переменной, ссылающейся на массив. Количество элементов динамического массива определяется процедурой SetLength. Функция Length возвращает количество элементов в динамическом массиве.

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

    var A, B: array of Integer; begin SetLength(A, 1); SetLength(B, 1); A[0] := 2; B[0] := 2; {A[0] = B[0] вернет значение True} {A = B вернет значение False} end.

    Для усечения динамического массива можно использовать функцию Copy.

    Например:

    var A: array of Integer; begin SetLength(A, 50); {Оставляет 10 элементов массива A} A := Copy(A, 0, 10); end.

    Если при объявлении функции или процедуры формальный параметр определяется как array of тип_массива, то эта функция или процедура может получить в качестве фактического параметра любой динамический или статический массив указанного типа вне зависимости от его размера и индексации его элементов.

    Множества

    язык Object Pascal предоставляет два простых типа, описывающих множества значений. Это:
  • порядковый тип - задающий множество значений внутри указанного интервала;
  • перечислимый тип - задающий множество значений, перечисленных внутри фигурных скобок и через запятую.

  • Множество языка Object Pascal - это набор значений порядкового или перечислимого типа. Множество определяется ключевым словом set of.
    Создание порядкового и перечислимого типов имеет следующее формальное описание:
    Идентификатор = Начальное_значение .. Конечное_значение; Идентификатор = {Значение_i .,...}; Идентификатор = Значение_i..Значение_j; Идентификатор = set of порядковый или перечислимый тип.
    Например:
    type {Объявление перечислимого типа} TMyColor = {Red,Blue,Yellow}; {Объявление типа множество} TMyClr = set of TMyColor; var {Объявление переменных созданных типов} ValC1, ValC2: TMyClr; begin {Присвоение значения переменной типа множество} ValC1 := [Blue]; ValC2 := ValC1+[ Red]; end.
    Начальным и конечным значением интервала для порядкового типа могут быть:
  • символы из кодовой таблицы ASCII (например, цифры или буквы);
  • любой диапазон значений ранее объявленного перечислимого типа.

  • Перед работой с переменной множественного типа ее следует проинициализировать. Значения инициализации указываются в квадратных скобках.
    Например:
    type TMyInts = 1..500; TIntSet = set of TMyInts; {Объявление переменной типа множества} var set1: TIntSet; begin {Инициализация переменной типа множества} set1:=[1,2,3,4]; end.
    Над множеством допустимы следующие операции:
  • объединение множеств (+);
  • разность (-);
  • умножение (*);
  • сравнение (<=, >=, =, <>);
  • принадлежность множеству (in).

  • Например:
    type {Порядковый тип: значения от 1 до 9} CountType = 1..9; LowerCharType = а..я; AType = (A1, A2, A3, A4, A5); {Порядковый тип: значения A3, A4 и A5} AType3 = A3..A5; {Множество на основе порядкового типа} ATypeSet = set of AType3; {Множество LetterType } LetterType = set of 'A'..'Z'; var {Объявление переменной типа множества} aset: ATypeSet; begin {Присвоение значения переменной множественного типа} aset:= [A3] + [A4]; {Вычитание множеств} aset:= aset - [A4]; end.
    Каждая переменная множественного типа может иметь значение - множество. Для изменения значений переменной множественного типа могут использоваться операции объединения (+) и разности (-) множеств.
    Например:
    begin set1:=set1 +[5,6]; end.
    Для определения принадлежности значения некоторому множеству используется операция in.
    Например:
    begin if 5 in set1 then ShowMessage( 'Значение принадлежит множеству set1'); end.

    Объявление производного типа

    Кроме базовых типов данных, рассмотренных в лекции 6, язык Object Pascal предоставляет простые и структурированные типы данных.
    Используя базовые, простые и структурированные типы данных, можно создавать производные типы данных.
    Напомним, что к базовым типам относятся:
  • целочисленный тип;
  • действительный тип;
  • логический тип;
  • символьный тип;
  • строковый тип.

  • К простым типам относятся:
  • порядковый тип;
  • перечислимый тип.

  • К структурированным типам относятся:
  • множества;
  • массивы;
  • записи;
  • файлы;
  • объектный тип (тип класса);
  • тип ссылки на класс.

  • Для того чтобы создать переменную производного типа, сначала следует определить этот производный тип. Объявление нового производного типа указывается ключевым словом type.
    Объявление произвольного типа как нового имени существующего типа в языке Object Pascal имеет следующее формальное описание:
    type имя_нового_типа = имя_существующего_типа;
    Объявление произвольного типа как нового типа в языке Object Pascal имеет следующее формальное описание:
    type имя_нового_типа = type имя_существующего_типа;
    При объявлении произвольного типа как нового имени типа, тип переменных производного типа и типа, используемого для его создания, будет совпадать. Если перед именем существующего типа указать ключевое слово type, то компилятор создаст новый тип. При этом указание в качестве формального параметра подпрограммы переменной существующего типа, а в качестве фактического параметра подпрограммы - переменной нового типа, созданного на базе данного существующего типа, вызовет для var-параметров ошибку времени компиляции.
    В языке Object Pascal объявление типов и переменных может быть выполнено только в определенных местах программы: секция объявления типа type используется для объявлений типов, а секция var для объявления переменных.
    Например:
    type TValReal1 = Real; var // Переменные X и Y имеют // один и тот же тип X: Real; Y: TValReal1; Е type TValReal2 = type Real; var // Переменные X и Y имеют разные типы X: Real; Y: TValReal2;

    Записи

    Запись представляет собой структуру, состоящую из набора полей различных типов. Каждый элемент записи называется полем. Каждое поле имеет свой идентификатор и свой тип.
    Запись может иметь поля двух видов:
  • фиксированные поля, которые всегда присутствуют в создаваемом экземпляре записи;
  • вариантные поля (располагаются только после фиксированных полей), для которых память при создании экземпляра записи выделяется только под одно самое наибольшее поле из варианта.

  • Объявление типа записи завершается ключевым словом end;.
    Например:
    type MyDateRec = record Year: Integer; Month: 1..12; Day: 1..31; end; var {Объявление переменных} Record1, Record2: MyDateRec; begin {Доступ к полям записи: } Record1.Month := 11; Record1.Day := 22; {Доступ к полям записи:} with Record1 do begin Year := 2004; Month := 11; Day := 22; end; {Копирование значений полей записей одного типа } Record2:= Record1;
    Переменная типа записи может быть объявлена одновременно с определением полей записи.
    Например:
    var S: record Name: string; Age: Integer; end;
    Запись, состоящая из одних вариантных полей, реализует тип, в некотором роде аналогичный типу union для языка С++.
    Вариантные поля позволяют на основе одного типа записи создавать экземпляры записей, содержащие поля разных типов. Это позволяет значительно экономить память.
    Объявление записи имеет следующее формальное описание:
    type имя_типа_записи = record список_полей: тип; {фиксированные поля} ... case тег: тип_варианта of {вариантные поля} константа_или_список: (вариант_1); ... константа_или_список: (вариант_n); end;
    Описание каждого фиксированного поля состоит из его идентификатора (или списка идентификаторов) и типа. Описания полей разделяются точкой с запятой. Вариантная часть объявления записи начинается с зарезервированного слова case.
    При определении вариантной части тег и символ двоеточия могут быть опущены в том случае, если тип_варианта описывает существующий тип или каждая константа (константа_или_список) в вариантной части является значением типа тип_варианта.
    Тип варианта не может быть длинной строкой, динамическим массивом, типом Variant или интерфейсом, но он может быть указателем на эти типы.
    Например:
    type TPerson = record FirstName, LastName: string[40]; case bl: Boolean of {Вариантные поля} True: (str1: string[40]); False: (str2: string[20]; date1: TDate); end; TShapeList = (Rectangle, Circle, Other, Ellipse); TFigure = record case TShapeList of Rectangle: (Height, Width: Real); Circle: (Radius: Real); Ellipse, Other: (); end;
    Применяя вариантные поля, можно одинаково трактовать данные различных типов, используя для доступа к ним вариантные поля соответствующих типов.

    Введение в программирование

    Конструкторы класса

    Конструктором называется метод, вызываемый при создании объекта данного класса. Класс может иметь несколько конструкторов, отличающихся списком параметров.
    Деструктором называется метод, вызываемый при разрушении объекта данного класса. Имена конструктора и деструктора совпадают с именем класса, но перед именем деструктора указывается символ ~.
    При создании объектов последовательно вызываются конструкторы всех его базовых классов. Вызов деструкторов при уничтожении объекта происходит в обратном порядке.
    Если конструктор базового класса имеет список параметров, то для его использования в производном классе следует создать конструктор производного класса с таким же списком параметров.
    При создании нового класса среда Visual C++ автоматически создает заголовочный файл и файл реализации класса с конструктором и деструктором без параметров.

    Квалификация имен

    Квалификация имен используется для однозначного понимания указываемого имени.
    Для квалификации имени могут использоваться следующие операторы: :: (оператор принадлежности); . (оператор доступа к члену класса посредством имени); -> (оператор доступа к члену класса через указатель). Квалификация имен

    Объектно-ориентированное программирование на языке С++

    В настоящее время понятие языка программирования неотрывно связано со средой программирования, в которой разрабатываются приложения. Для языка С++ наиболее развитыми и популярными средами программирования являются:
  • Visual Studio.NET;
  • С++ Builder.

  • Среда программирования Visual Studio.NET предназначена для создания приложений не только на языке С++, но и на таких популярных языках, как C# и Visul Basic. Иногда для сокращения говорят, что проектирование приложений на C++ в Visual Studio.NET реализуется средой Visual C++.
    Visual C++ позволяет разрабатывать приложения как в терминах традиционного модульного программирования, так и с применением объектно-ориентированного программирования.

    Объектные типы

    Тип данных всегда определяет размер памяти, которая будет выделена под переменную данного типа при ее создании.
    При объявлении переменной объектного типа (типа класса) создаются переменные члены класса и вызывается конструктор класса. Производные типы на основе классов позволяют получать доступ к членам класса.
    Переменная, объявленная как указатель на класс, применяется для доступа к методам и переменным членам класса. В следующей таблице приведен синтаксис, используемый при работе с указателями на члены класса.
    Hапример:
    #include class A // Объявление класса A { public: int j1; A(void); ~A(void);}; void main() { int A::*pToj = &A::j1; // Объявление производного типа pToj // как указателя на член класса j1 A jA; // Объявление переменной объектного типа A A *pjA = & jA; // Объявление указателя на эту // переменную (объект) int j; jA.*pToj = 123; // Присваивание значения переменной // jA::j1, используя * j = pjA ->*pToj; // Получение значения, используя ->* std::cout << j << "\n"; }

    Объявление и реализация класса в языке С++

    Создаваемый класс должен быть объявлен и реализован.
    Объявление класса в языке С++ может иметь следующее формальное описание:
    class имя_класса : список_базовых_классов { public: // Модификатор доступа относится // ко всем перечисленным после // него членам до следующего // модификатора доступа // Объявление общедоступных членов класса
    protected: // Объявление членов класса, доступных // только для производных классов
    private: // Объявление защищенных членов класса };
    Список базовых классов указывается после имени класса через символ двоеточия (:), разделяется запятыми и может иметь модификаторы доступа.
    Например:
    class MyClass : public ClassA, public ClassB, private ClassC {};
    В языке С++ считается, что если модификатор доступа для класса или члена класса не указан, то по умолчанию предполагается модификатор доступа private (защищенный доступ). Для членов структур, объявляемых ключевым словом struct, по умолчанию модификатор доступа предполагается равным public.
    Модификатор доступа базового класса позволяет определить, какие переменные и методы базового класса будут доступны из производного класса. Модификатор доступа, указываемый перед именем базового класса, определяет следующие правила доступа к переменным и методам базового класса из производного класса:
  • public - в производном классе доступны все переменные и методы базового класса с модификаторами доступа public и protected, и эти члены класса имеют те же права доступа;
  • protected - члены базового класса с модификаторами доступа public и protected доступны как protected, а с модификатором доступа private - недоступны.
  • private - члены базового класса с модификаторами доступа public и protected доступны как private, а с модификатором доступа private - недоступны.

  • Например:
    class BaseClass { public: int PublicFunc(); protected: int ProtectedFunc(); private: int PrivateFunc(); }; class DerivedClass1 : public BaseClass { // Наследуемая функция PublicFunc доступна // как public // Наследуемая функция ProtectedFunc // доступна как protected }; class DerivedClass2 : private BaseClass { // Наследуемая функция PublicFunc доступна // как private // Наследуемая функция ProtectedFunc // доступна как private }; int main() { }
    В теле объявления класса указываются модификаторы доступа, описывающие права доступа для переменных и методов класса:
  • модификатор доступа относится ко всем перечисленным после него членам до следующего модификатора доступа;
  • один и тот же модификатор доступа может указываться несколько раз;
  • после модификатора доступа ставится символ двоеточие;
  • если модификатор доступа не указан, то по умолчанию предполагается private.

  • Для доступа к членам класса используется операция принадлежности ::, указываемая после идентификатора класса. Для доступа к членам экземпляра класса используются операции . и ->.
    Для доступа к объекту самого класса внутри метода члена класса используется ключевое слово this.
    Например:
    class A { public: int i; Func1();} A:: Func1() { return this->i; } // this - указатель класса A

    Преобразование объектных типов

    Указатель на класс может быть преобразован к указателю на базовый класс в двух случаях:
  • если базовый класс является доступным и преобразование однозначно;
  • если указано явное преобразование типа указателя.

  • Например:
    class A // А - базовый класс {public: int a1; int Fa(); }; class B : public A // В - производный класс {public: int b1; int Fb(); }; B bObj; // Объект типа B A *pA = &bObj; // Преобразование типа ограничивает // доступ к членам класса B и // разрешает доступ только к членам // базового класса B *pB = &bObj; // Нет преобразования типа и // следовательно разрешен доступ как // к членам класса B, // так и к членам класса А. pA-> Fa (); // Правильно: вызов функции члена класса A. pB-> Fa (); // Правильно: вызов функции, //наследуемой от класса A // Вызов pA-> Fb (); ошибочен: функция Fb // недоступна через указатель на базовый // класс А
    Указатели на члены класса или структуры не могут рассматриваться как обычные указатели и для них не выполняется стандартное преобразование типа.

    Создание объекта

    Для создания объекта (экземпляра данного класса) следует объявить переменную типа указатель на класс, а затем создать объект, выполнив оператор new с указанием используемого конструктора.
    Например:
    A* ca; ca= new A();
    Эти же действия можно записать одним оператором.
    Например:
    A* ca= new A();
    Для того чтобы можно было использовать конструктор с параметрами, значения параметров необходимо указать при создании объекта.

    Структура приложения на языке С++

    Приложение состоит из модулей трансляции - файлов исходного кода на языке С++. Каждый модуль трансляции представляется файлом реализации класса и заголовочным файлом (компилятор позволяет записывать всю информацию - объявление и реализацию, в один файл, но это оправданно только для маленьких программ).
    Проектом в терминологии Visual C++ называется совокупность всех модулей трансляции, файлов ресурсов и описания конфигурации.
    Разработка любого приложения в Visual C++ начинается с создания проекта. Visual Studio.NET предоставляет шаблоны для создания различных видов приложений (консольные приложения, MFC-приложения, DLL-библиотеки, приложения управляемого кода и т.п.).
    Консольное приложение - это приложение, не использующее Windows-окна для обработки сообщений от пользователя. Точкой входа в консольное приложение в языке С++ является метод main.
    После того как создан шаблон приложения заданного вида, информация обо всех файлах проекта отображается в окне проектов среды Visual C++.
    Заголовочный файл содержит объявления используемых данных. Язык C++ поддерживает соглашение о раздельной компиляции: каждый С++-модуль можно компилировать отдельно. Для того чтобы несколько модулей могли использовать одни и те же данные, объявление этих данных выносят в заголовочный файл. Принято, что имя заголовочного файла имеет расширение h.
    Все подключаемые к модулю заголовочные файлы указываются в начале модуля директивой препроцессора #include.
    Например:
    #include "stdafx.h" #include
    Имя подключаемого файла в директиве препроцессора #include может быть указано:
  • в двойных кавычках - в этом случае препроцессор сначала выполняет поиск данного файла в том же каталоге, в котором расположен файл, содержащий директиву препроцессора #include, а затем в каталогах, определяемых опцией компиляции и переменной среды INCLUDE.
  • в угловых скобках - при этом исключается поиск имени файла в том же каталоге, в котором расположен файл, содержащий директиву препроцессора #include.

  • Файл, содержащий реализацию методов, объявленных в заголовочном файле, иногда называется исходным файлом.
    Каждая программа должна иметь точку входа и может содержать описание одного или нескольких классов.
    Точкой входа в программу в приложении, формируемом по шаблону в среде Visual C++, является метод _tmain, заменяемый при компиляции на метод main.
    Минимальной программой на С++ является следующий код:
    int main() {}
    Эта программа определяет функцию с именем main, которая не использует параметров и не выполняет никаких действий.
    Тело метода в языке С++ указывается в фигурных скобках. Перед именем метода указывается тип возвращаемого значения. Если метод не возвращает никакого значения, то его тип обозначается ключевым словом void.

    Терминология объектно-ориентированного программирования

    Объектно-ориентированное программирование позволяет оперировать в терминах классов: определять классы, конструировать производные классы, создавать объекты, принадлежащие классу, - экземпляры класса.
    Сначала в некоторых языках программирования появился тип struct, расширением которого стал тип class.
    Класс определяет данные (переменные) и поведение (методы). Данные и методы класса также называют членами класса. Класс рассматривается как определяемый пользователем тип данных.
    Объектом называется экземпляр некоторого класса. Объект создается как переменная типа класса, которая используется для доступа к данным - членам класса и для вызова методов - членов класса.
    Наследованием называется механизм, позволяющий производному классу наследовать структуру данных и поведение другого класса, а также наследовать поведение, объявленное в интерфейсах и абстрактных классах.
    Наследование позволяет определять новые классы в терминах существующих классов.
    В объектно-ориентированном программировании наследование может быть:
  • множественным, позволяющим производному классу наследоваться одновременно от нескольких классов (например, так реализован механизм наследования в С++);
  • простым, когда производный класс имеет только один наследуемый класс (например, так реализованы языки Java и Object Pascal).

  • Наследуемый класс принято называть базовым классом, или родительским классом (классом - предком, суперклассом).
    Производный класс, наследующий структуру данных и поведение своего базового класса, иногда также называется дочерним классом (классом - потомком, подклассом).
    В производном классе можно переопределять методы базового класса и добавлять новые методы. Непосредственным базовым классом называется класс, от которого порожден производный класс следующего уровня иерархии:
       А   Базовый класс класса С и непосредственный базовый класс класса B
       ?    
       B   Непосредственный базовый класс класса C
       ?    
       C   Производный класс

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

    Вложенные классы

    Язык С++ допускает использование вложенных классов - внутри тела одного класса содержится объявление других классов.
    Например:
    class A { public: A(void); ~A(void); class B { // Вложенный класс B(void) {}; ~B(void) {}; char sStr2[3]; };
    };

    Введение в программирование

    Дружественные члены класса

    Дружественные члены класса (методы) позволяют получить доступ к защищенным модификатором private членам класса из методов других классов. Методы и классы, объявляемые дружественными, иногда также называются друзьями класса.
    Если метод класса A внутри тела класса B объявляется с модификатором friend, что указывает на то, что он является другом класса, то из него разрешен доступ ко всем членам класса B.
    Например:
    class A { public: int Fx();} class B { public: friend int A::Fx(); private: }

    Дружественные классы

    Объявление дружественного класса позволяет всем его методам получить доступ ко всем переменным и методам другого класса.
    Например:
    class A {public: int Fx();} class B {public: friend class A; private: }
    Дружественный класс или член класса будет доступен только в том случае, если он был объявлен в области видимости самого класса или ранее во внешней области видимости, внутри которой располагается область видимости, содержащая объявление класса с объявлениями друзей класса.
    Например:
    class A {public: // Класс расположен во внешней // области видимости int Fx1(); } namespace classB { class B {public: friend class A; friend class C; private: } class C { public: // Класс расположен в том же // пространстве имен int Fx2(); } }
    Дружественные классы не наследуются, и их дружественность не является транзитивной.
    Например:
    class A {int Fx();} class B {friend class A;} class C {friend class B;} // Класс А не является // дружественным классу C class D : public B {} // Класс А не является // дружественным классу D
    Дружественные классы

    Методы-члены класса

    В терминологии объектно-ориентированного программирования функции также называются методами или методами - членами класса, для того чтобы подчеркнуть, что конкретная функция является членом некоторого класса.
    По стандарту ANSI C, используемому компилятором Visual C++, любая используемая в модуле компиляции функция должна иметь прототип, включающий в себя тип функции, имя функции и список параметров с их типами. Прототип - это некоторое предварительное описание функции, заканчивающееся символом ;.
    Прототип функции должен быть вставлен во все модули компиляции, использующие функцию. Для небольших программ прототип функции обычно записывается в модуль компиляции. Для программ, создаваемых средствами Visual C++, и программ, состоящих из нескольких модулей, прототип функции указывается в заголовочном файле. Объявление функции должно однозначно соответствовать ее прототипу и может находиться в любом модуле компиляции (для которого доступен прототип функции).
    Прототип метода, являющегося членом некоторого класса, записывается в заголовочном файле, содержащем объявление класса в теле этого класса.
    Метод - член класса может иметь следующие модификаторы доступа:
  • public - общедоступный метод;
  • protected - метод, доступный только для членов и объектов данного класса и наследуемых классов (наследуемых с модификаторами доступа public или protected);
  • private - защищенный метод, доступный только внутри класса.

  • Прототип метода может иметь следующее формальное описание:
    модификатор_доступа тип_метода имя_метода (список_параметров);
    Объявление метода может иметь следующее формальное описание:
    модификатор_доступа тип_метода имя_метода (список_параметров) { тело_метода }
    Тип метода является типом возвращаемого методом значения и может быть любым допустимым базовым или производным типом, включая и тип указателя.
    Указатели типа void могут использоваться для объявления параметров метода в том случае, если тип этих параметров на момент компиляции неизвестен.
    Например:
    void Fx(void *pV); //Прототип метода ...
    piVar=new int; pfVar=new float; Fx(piVar); // Вызов метода для // параметра типа int Fx(pfVar); // Вызов метода для // параметра типа float ... // Реализация метода void Fx(void *pV) {*pV=12345;}

    Метод, возвращающий указатель, записывается следующим образом:

    тип *имя_метода(список_параметров).

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

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

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

    Список параметров может включать параметры, имеющие значения по умолчанию. Такие параметры указываются в конце списка параметров. Значение по умолчанию будет использовано только в том случае, если число переданных параметров меньше числа указанных формальных параметров в описании метода.

    Язык C++ разрешает рекурсивный вызов методов.

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

    Методы с переменным числом параметров

    Метод может иметь переменное число параметров: это указывается в конце списка параметров символом многоточия ... . Методы с переменным числом параметров должны иметь как минимум один описанный формальный параметр.
    Для применения переменного числа параметров можно использовать:
  • макрос va_start(указатель_списка_параметров,последний_параметр) - при инициализации указателя и установке его на начало переменного списка параметров;
  • макрос va_arg(указатель_списка_параметров,i) - при выборе параметра и продвижении указателя в соответствии с его типом на следующий параметр;
  • макрос va_end((указатель_списка_параметров) - при установке указателя на список параметров, равный null, после извлечения значений всех параметров;
  • тип va_list - для создания указателя на список параметров.

  • Например:
    #include // Библиотека, содержащая тип va_list #include #include int Fx ( int i1, ... ); // Прототип Функции с переменным // числом параметров void main( void ) { // Вызов функции Fx с различным // числом параметров std::cout<< Fx ( 100, 200) ); std::cout<< Fx ( 5 ) ); std::cout<< Fx ( -1,-3,45 ) ); } int Fx ( int i1, ... ) // Реализация функции с переменным // числом параметров { int sumx,i; sumx = 0, i = i1; va_list list1; // Список параметров va_start(list1, i1 ); // Инициализация списка параметров while( i != -1 ) { sumx += i; i = va_arg(list1, int); //Извлечение следующего параметра } va_end(list1); return( sumx ); }

    Перегрузка функций и методов

    Язык C++ позволяет выполнять перегрузку функций и методов - членов класса, то есть вызывать функцию (метод) с тем же именем, но с различными типами фактических параметров. Для создания перегружаемой функции следует указать отдельный прототип и сделать отдельное объявление для каждого списка параметров. Если функции различаются только типом и имеют совпадающие списки параметров, то для таких функций перегрузка не допускается.
    Для определения вызываемой перегружаемой функции учитываются только списки параметров, а тип возвращаемого значения не учитывается. При этом для соответствия списка параметров вызываемой функции может применяться преобразование типов и соответствие по многоточию (соответствие по многоточию?) для функций с переменным числом параметров.

    Создание метода-члена класса

    Для того чтобы в среде Visual Studio .NET добавить в класс новый метод - член класса, следует в окне просмотра классов Class View выделить секцию с именем класса и выполнить команду контекстного меню Add|Add Function, а затем в диалоге - мастере построения метода ввести имя метода, его тип, а также определить список параметров.
    При добавлении метода - члена класса в файл реализации класса автоматически добавляется код реализации нового метода, а в заголовочный файл - объявление этого метода.

    Указатели на методы-члены класса и на функции

    Указатели на методы и на функции могут быть использованы для передачи метода в качестве параметра другому методу.
    Объявление указателя на метод может иметь следующее формальное описание:
    тип_метода (имя_класса::*имя_метода_указателя) (список параметров); тип_функции (*имя_ функции_указателя) (список параметров);
    Инициализация указателя может иметь следующее формальное описание:
    тип_метода имя_класса::*имя_метода_указателя (список параметров)= &имя_класса::имя_любого_метода; тип_функции (*имя_ функции_указателя) (список параметров)= &имя_функции;
    Вызов метода, объявленного как указатель на метод, может быть выполнен следующим образом:
    (имя_объекта->*имя_ метода_указателя) (список параметров); (*имя_ функции_указателя)(список параметров);
    Для функций, но не для методов - членов класса, разрешена другая форма вызова метода:
    имя_ функции_указателя(список параметров); (имя_ функции_указателя)(список параметров);
    Объявление функции, имеющей в качестве параметра указатель на метод, может иметь следующее формальное описание:
    тип_метода имя_метода (тип_метода_указателя (*имя_метода_указателя) (список параметров));
    Вызов метода, использующего в качестве параметра указатель на метод, может иметь следующее формальное описание:
    имя_метода(имя_объекта->*имя_метода_указателя); имя_функции(имя_функции_указателя);
    Разрешается создавать массив указателей на функции.
    При использовании указателей на функцию можно не употреблять операцию разыменования или операцию получения адреса.
    Например:
    class a1 { public: a1(void); ~a1(void); int Fx1(int i1); int Fx2(int i2); }; a1::a1(void){} a1::~a1(void){} int a1::Fx1(int i1){ return 1;} int a1::Fx2(int i2){ return 2;}
    int (*Fy_pointer)(); // Объявление указателя на функцию int Fy (); int _main(int argc, char* argv[]) { a1* a1Object = new a1(); int (a1::*Fx_pointer)(int)=&a1::Fx2; // Объявление и инициализация указателя // на метод - член класса int i; i=(a1Object->*Fx_pointer)(1); // Вызов по указателю на метод std::cout<

    Встроенные функции

    Встроенные функции указываются оператором inline. Применение встроенных функций может несколько сократить время выполнения программы, так как компилятор встраивает код такой функции в том месте программы, где указан ее вызов.
    Например:
    inline void Fx(void) { std::cout<<"Функция Fx"<

    Введение в программирование

    Абстрактные классы

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

    Указатель на объект класса

    class A // Объявление базового класса { public: virtual void VirtMetod1(); // Виртуальный метод void Metod2(); // Не виртуальный метод }; void A::VirtMetod() { cout << "Вызван A::VirtMetod1\n";}

    void A::Metod2() { cout << "Вызван A::Metod2\n"; }

    class B : public A // Объявление производного класса {public: void VirtMetod1(); // Виртуальный метод void Metod2(); // Не виртуальный метод }; void B::VirtMetod1() { cout << "B::VirtMetod1\n";} void B::Metod2() { cout << "B::Metod2\n"; } void main() { B aB; // Объект класса B B *pB = &aB; // Указатель на объект класса B A *pA = &aB; // Указатель на объект класса A pA->VirtMetod1(); // Вызов метода VirtMetod класса B pB->VirtMetod1(); // Вызов метода VirtMetod класса B pA->Metod2(); // Вызов метода Metod2 класса A pB->Metod2(); // Вызов метода Metod2 класса B }

    Пример 12.1. Вызов виртуальных методов
    Закрыть окно





    class A // Объявление базового класса

    { public:

    virtual void VirtMetod1(); // Виртуальный метод

    void Metod2(); // Не виртуальный метод

    };

    void A::VirtMetod() { cout << "Вызван A::VirtMetod1\n";}

    void A::Metod2() { cout << "Вызван A::Metod2\n"; }

    class B : public A // Объявление производного класса

    {public:

    void VirtMetod1(); // Виртуальный метод

    void Metod2(); // Не виртуальный метод

    };

    void B::VirtMetod1() { cout << "B::VirtMetod1\n";}

    void B::Metod2() { cout << "B::Metod2\n"; }

    void main() {

    B aB; // Объект класса B

    B *pB = &aB; // Указатель на объект класса B

    A *pA = &aB; // Указатель на объект класса A

    pA->VirtMetod1(); // Вызов метода VirtMetod класса B

    pB->VirtMetod1(); // Вызов метода VirtMetod класса B

    pA->Metod2(); // Вызов метода Metod2 класса A

    pB->Metod2(); // Вызов метода Metod2 класса B

    }

    Реализация методов шаблона класса template

    template // Описание шаблона класса class A { T1 x,y; public: A(); ~A(); T1 Fx(); void Fy(T1 a, T1 b); }; template A< T1>::A() {} // Реализация методов шаблона класса template A< T1>::~A() {} template T1 A< T1>::Fx(){ return x*y;} template void A< T1>::Fy(T1 a, T1 b) {x=a; y=b;}

    int main(int argc, char* argv[]) { int i1=1; int i2=2; double x=1.5; double y=2.5; A F1; // Создание объекта с использованием шаблона класса A *pF1=&F1; // Указатель на объект параметризированного типа pF1->Fy(i1,i2); std::cout<Fx()< F2; A *pF2=&F2; pF2->Fy(x,y); std::cout<Fx()<
    Пример 12.2. Создание объекта на основе шаблона класса
    Закрыть окно





    template // Описание шаблона класса

    class A

    {

    T1 x,y;

    public:

    A();

    ~A();

    T1 Fx();

    void Fy(T1 a, T1 b);

    };

    template A< T1>::A() {} // Реализация методов шаблона класса

    template A< T1>::~A() {}

    template T1 A< T1>::Fx(){ return x*y;}

    template void A< T1>::Fy( T1 a, T1 b) {x=a; y=b;}

    int main(int argc, char* argv[])

    { int i1=1;

    int i2=2;

    double x=1.5;

    double y=2.5;

    A F1; // Создание объекта с использованием шаблона класса

    A *pF1=&F1; // Указатель на объект параметризированного типа

    pF1->Fy(i1,i2);

    std::cout
    A *pF2=&F2;

    pF2->Fy(x,y);

    std::cout

    Работа с памятью

    Свободная память, которую можно заказывать в процессе выполнения программы, называется динамической памятью. Для выделения непрерывного блока памяти можно использовать функцию malloc(), а для освобождения - функцию free(). Прототипы этих функций расположены в заголовочном файле stdlib.h.
    Например:
    int *pIntBuffer; // Выделение памяти под 5 переменных типа int pIntBuffer=malloc(5*sizeof(int));
    При отсутствии требуемого количества памяти функция malloc возвращает значение null.
    Выделение динамической памяти также можно выполнять оператором new, а освобождение - оператором delete. Оператор new автоматически учитывает тип объекта и выделяет требуемое количество памяти.
    Пример:
    double *pBuffer; // Выделение памяти под 10 переменных типа double pBuffer=new double [10];
    Работа с памятью

    Шаблоны классов

    Шаблоны классов позволяют определить параметризированный тип.
    Шаблоны классов аналогично шаблонам функций позволяют на этапе компиляции создавать определения классов.
    Шаблон класса указывается ключевым словом template, за которым в угловых скобках указывается список типов для создания параметризированного класса. Имя шаблона класса указывается после ключевого слова class.
    Для создания объекта на основе шаблона класса после имени шаблона в угловых скобках указывается конкретный тип:
    имя_шаблона_класса <тип> имя_объекта.
    Например:
    template // Описание шаблона класса class A { T1 x,y; public: A(); ~A(); T1 Fx(); void Fy(T1 a, T1 b); }; template A< T1>::A() {} // Реализация методов шаблона класса template A< T1>::~A() {} template T1 A< T1>::Fx(){ return x*y;} template void A< T1>::Fy(T1 a, T1 b) {x=a; y=b;}
    int main(int argc, char* argv[]) { int i1=1; int i2=2; double x=1.5; double y=2.5; A F1; // Создание объекта с использованием шаблона класса A *pF1=&F1; // Указатель на объект параметризированного типа pF1->Fy(i1,i2); std::cout<Fx()< F2; A *pF2=&F2; pF2->Fy(x,y); std::cout<Fx()< Пример 12.2. Создание объекта на основе шаблона класса

    Шаблоны методов

    Шаблоны методов позволяют описывать одинаковую реализацию для различных типов параметров.
    Шаблон метода позволяет описать одну реализацию метода для всех допустимых значений параметров. Фактически шаблон метода заменяет набор перегружаемых методов с различными типами параметров.
    Шаблон метода - это еще одно проявление полиморфизма языка С++.
    Шаблоны методов используют в качестве параметра тип переменной.
    В момент компиляции при вызове метода, не имеющего прототипа, выполняется поиск шаблона метода, из которого вызываемый метод может быть сгенерирован.
    Шаблон метода указывается ключевым словом template, за которым в угловых скобках указывается список типов, используемых для параметров функции и типа возвращаемого значения.
    Например:
    template T1 Fx (T1 x, T1 y) {return x+y;}
    При использовании шаблона компилятор заменит для вызываемого метода тип шаблона на тип, указанный при вызове метода (T1 на int в следующем примере).
    Например:
    int i1=1; int i2=2; std::cout<

    Статические члены класса

    Переменные и члены класса, объявленные с модификатором доступа static, называются статическими членами класса. Cтатические переменные и методы доступны без создания объекта данного класса. Имя статической переменной квалифицируется именем класса с использованием операции принадлежности :: , а не именем экземпляра класса.
    Например:
    class A { public: static int iStat; }; int main(int argc, char* argv[]) { A:: iStat = 123; }
    Статические методы могут вызывать и использовать только другие статические методы и статические переменные. Из статического метода нельзя выполнять вызов не статического метода - члена класса.
    Статическую переменную можно рассматривать как аналог глобальной переменной, которая связана с конкретным классом.
    Часто статические переменные называют переменными класса, а не статические переменные - переменными экземпляра.
    Для статических переменных могут использоваться указатели.
    Например:
    class A { public: static int iStatVar; }; int main(int argc, char* argv[]){ int A:: iStatVar = 0; int *piStatVar = &A:: iStatVar; }
    При использовании статических переменных указатели всегда являются указателями на существующий тип (в данном примере на тип int), а не на тип класса.
    Для того чтобы создать и использовать статическую переменную, следует:
  • Объявить (как правило, в заголовочном файле) статическую переменную как член класса.
    Например: static int iStat;.
  • Для выделения памяти под эту переменную ее повторно следует объявить в модуле компиляции, в котором она будет использоваться, квалифицируя имя статической переменной именем класса.
    Например: int A::iStat;
  • Выполнить инициализацию статической переменной (по умолчанию статическая переменная типа int имеет значение 0).
    Например: A::iStat=123;

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

    имя_класса::имя_конструктора : имя_стат_переменной(значение) { }

    нельзя ни в каком случае.

    Для того чтобы создать статический метод - член класса в среде Visual C++, достаточно выделить в окне Class View секцию с именем класса, в который будет вставлен создаваемый метод, и выполнить команду контекстного меню Add|Add Function. А затем определить тип и имя создаваемого метода, список параметров, и отметить флажок Static, указывающий на то, что создаваемая функция будет статической.

    В результате выполненных действий среда Visual C++ добавит в заголовочный файл класса прототип создаваемой статической функции, а в файл реализации - код реализации создаваемой статической функции.

    Например:

    class A {public: a1(void); ~a1(void); int Fx1(int i1); int Fx2(int i2); protected: static int Fstat1(void); // Статическая функция доступна //только для статических методов - членов //данного класса и наследуемых классов public: static int Fstat2(void); // Общедоступная статическая функция };

    int main(int argc, char* argv[]){ std::cout<
    Реализация статической функции записывается так же, как и реализация любого другого метода - члена класса. При этом ключевое слово static не указывается.

    Например:

    int A::FStat1(void) { return 0; }

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

    Для того чтобы при множественном наследовании один и тот же базовый класс не порождал для объекта производного класса несколько объектов базового класса, при объявлении производного класса такой базовый класс указывается с ключевым словом virtual и называется виртуальным классом.
    Например:
    class A : virtual public B { }

    Виртуальные методы

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

  • В следующем примере иллюстрируется вызов виртуальных методов:
    class A // Объявление базового класса { public: virtual void VirtMetod1(); // Виртуальный метод void Metod2(); // Не виртуальный метод }; void A::VirtMetod() { cout << "Вызван A::VirtMetod1\n";}
    void A::Metod2() { cout << "Вызван A::Metod2\n"; }
    class B : public A // Объявление производного класса {public: void VirtMetod1(); // Виртуальный метод void Metod2(); // Не виртуальный метод }; void B::VirtMetod1() { cout << "B::VirtMetod1\n";} void B::Metod2() { cout << "B::Metod2\n"; } void main() { B aB; // Объект класса B B *pB = &aB; // Указатель на объект класса B A *pA = &aB; // Указатель на объект класса A pA->VirtMetod1(); // Вызов метода VirtMetod класса B pB->VirtMetod1(); // Вызов метода VirtMetod класса B pA->Metod2(); // Вызов метода Metod2 класса A pB->Metod2(); // Вызов метода Metod2 класса B }
    Пример 12.1. Вызов виртуальных методов
    Результатом выполнения этой программы будут следующие строки:
    Вызван B::VirtMetod1 Вызван B::VirtMetod1 Вызван A::Metod2 Вызван B::Metod2
    Чисто виртуальной функцией называется виртуальная функция, указанная с инициализатором
    =0.
    Например:
    virtual void F1( int) =0;
    Объявление класса может содержать виртуальный деструктор, используемый для удаления объекта определенного типа. Однако виртуального конструктора в языке С++ не существует. Некоторой альтернативой, позволяющей создавать объекты заданного типа, могут служить виртуальные методы, в которых выполняется вызов конструктора для создания объекта данного класса.
    Например:
    class A{ public: A(); A (const A&); virtual A* virt_object1 () { return new A(); } virtual A* virt_object2 () { return new A(*this); } }

    Введение в программирование

    Абстрактные классы

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

    Эквивалентность объектов

    Для определения равенства различных объектов применяется метод equals.
    Метод equals реализован в классе Object и соответственно наследуем любым классом Java. Большинство классов переопределяет этот метод таким образом, что позволяет сравнивать на эквивалентность объекты конкретного класса.
    Например:
    class A { String objectName; A (String name) { objectName = name; } // Конструктор } public class MyA { public static void main (String args[ ]) { A A = new A("Class1"); // Создание экземпляра класса
    A A_eq = A; // Ссылка на существующий объект
    A A_clon = (A)A.clone; // Создание объекта методом clone
    A A_2 = new A("Class2"); // Сравнение объектов: if (A.equals(A_eq)) { } if (A.equals(A_ clon)) { } if (A.equals(A_ 2)) { } } }
    Выполнив приведенный пример, можно увидеть, что эквивалентными будут только экземпляр класса и объект, созданный как ссылка на данный экземпляр класса. А экземпляр класса и его клон, так же, как и различные экземпляры одного класса, не совпадают.
    Принадлежность объекта к конкретному классу проверяется с помощью оператора instanseof.

    Механизмы наследования

    Класс - это шаблон, в котором определяются данные и поведение объекта. Объекты одного класса совместно используют общую структуру данных и общее поведение.
    Объявление класса в языке Java создает новый ссылочный тип, определяющий как описание методов, так и их реализацию.
    Объявление интерфейса создает новый ссылочный тип, который специфицирует описание методов и имена некоторых констант, но не определяет саму их реализацию.
    Интерфейс может быть объявлен для расширения одного или нескольких интерфейсов.
    Наследование позволяет определять новые классы в терминах существующих классов.
    В языке Java поддерживается только простое наследование: любой подкласс является производным только от одного непосредственного суперкласса. При этом любой класс может наследоваться от нескольких интерфейсов.
    Наследование интерфейсов реализует некоторую замену множественному наследованию, когда вместо того чтобы один класс имел несколько непосредственных суперклассов, этот класс наследует несколько интерфейсов. Интерфейс позволяет определить некоторый шаблон класса: описание методов без их реализации.
    Язык Java разрешает несколько уровней наследования, определяемых непосредственным суперклассом и косвенными суперклассами. Наследование можно использовать для создания иерархии классов.
    При создании подкласса на основе одного или нескольких суперклассов возможны следующие способы изменения поведения и структуры класса:
  • расширение суперкласса путем добавления новых данных и методов;
  • замена методов суперкласса путем их переопределения;
  • слияние методов из суперклассов вызовом одноименных методов из соответствующих суперклассов.


  • Объявление интерфейса

    Объявление интерфейса вводит новый ссылочный тип, членами которого являются константы и абстрактные методы.
    Реализация интерфейса всегда выполняется в классе, который использует данный интерфейс.
    Один класс может реализовывать несколько интерфейсов, и один интерфейс может использоваться несколькими классами.
    Интерфейсы позволяют разделять общую структуру - методы и константы, классами, не связанными между собой иерархией наследования.
    Объявление интерфейса может иметь следующее формальное описание:
    МодификаторИнтерфейса ИдентификаторИнтерфейса extends СписокНаследуемыхИнтерфейсов {ТелоИнтерфейса}
    Самым простым примером объявления интерфейса может быть следующий код:
    interface MyColors { int RED = 1, YELLOW = 2, BLUE = 4; }
    Интерфейс может иметь в качестве предков только интерфейсы.
    Интерфейс может иметь модификаторы public и abstract. Язык Java подразумевает, что каждый интерфейс по умолчанию имеет модификатор abstract, который не рекомендуется указывать явно.
    К интерфейсу, объявленному с модификатором доступа public, может быть произведен доступ из других пакетов, в противном случае - только из своего пакета.
    Тело интерфейса заключается в фигурные скобки и не может содержать конструктора или блоков инициализации статических переменных. В остальном тело конструктора идентично телу абстрактного класса.
    Любая переменная интерфейса по умолчанию считается переменной с модификаторами public, static и final и обязательно должна быть инициализирована константным выражением. Также каждая переменная в теле интерфейса неявно считается переменной с модификатором.
    Метод, объявленный в теле интерфейса, по умолчанию считается методом с модификаторами abstract и public. Объявление метода завершается точкой с запятой и не содержит тела метода, заключенного в фигурные скобки.
    Метод интерфейса не может иметь модификаторов final или static.
    Интерфейс можно использовать как ссылочный тип при объявлении переменных. Переменная или выражение типа интерфейса могут ссылаться на любой объект, который является экземпляром класса, реализующего данный интерфейс. Переменную типа интерфейса можно использовать только после присвоения ей ссылки на объект ссылочного типа, для которого был реализован данный интерфейс.

    Объявление класса

    Объявление класса вводит новый ссылочный тип и определяет или часть или всю его реализацию.
    При загрузке класса выделяется память для всех его статических переменных и затем выполняется их инициализация.
    Объявление класса может иметь следующее формальное описание:
    МодификаторыКласса class ИмяКласса extends ИмяСуперКласса implements СписокРеализуемыхИнтерфейсов {ТелоКласса}
    Тело класса содержит описание переменных, методов и вложенных классов и заключается в фигурные скобки. В частном случае тело класса может не содержать ни одного объявления.
    Например:
    public class A implements B { public A() { } public int Metod1(){return 0;} } interface B { public int Metod1(); }
    Вложенный класс описывается так же, как и внешний.
    В описании каждого класса указывается имя класса и тело класса, содержащее объявления полей класса. Дополнительно для класса могут быть заданы модификаторы класса и указан непосредственный суперкласс и реализуемые классом интерфейсы. Полями класса в Java называются переменные и методы, определяемые в теле класса.
    Класс может иметь более одного модификатора класса.
    В языке программирования Java существуют следующие модификаторы класса:
  • abstract, являющийся модификатором реализации класса и определяющий, что класс может иметь абстрактные методы (методы, не имеющие реализации);
  • final, являющийся модификатором ограничения иерархии классов и указывающий, что класс не может иметь подклассов (не должен никогда появляться во фразе extends объявления класса). Класс с модификатором final обязан реализовать все свои интерфейсы.
  • public является модификатором доступа и указывает, что к данному классу разрешен доступ из других пакетов. Доступ может быть выполнен или непосредственно указанием квалифицированного имени класса, или с использованием оператора import.

  • Для указания модификаторов класса применяются следующие правила:
  • если класс, имеющий абстрактные методы, объявлен без модификатора abstract, то возникает ошибка компиляции;
  • для абстрактных классов нельзя создавать экземпляры класса;
  • если при объявлении класса не указан модификатор public, то класс доступен только внутри своего пакета;
  • при компиляции каждый общедоступный класс всегда записывается в отдельный файл с расширением .CLASS.
    Такой файл называется модулем компиляции;
  • имя общедоступного класса должно совпадать с именем файла, содержащего код класса на языке Java;
  • один модуль компиляции может содержать только один класс или интерфейс, имеющие модификатор public;
  • один модуль компиляции может одновременно содержать объявление общедоступного класса и нескольких интерфейсов или классов, не имеющих модификатора public;
  • один модуль компиляции не может одновременно содержать объявление общедоступного класса (public class) и общедоступного интерфейса (public interface);
  • объявление класса одновременно с модификаторами final и abstract вызывает ошибку компиляции.


  • Любой класс может иметь только один суперкласс, указываемый ключевым словом extends. Наследуемый суперкласс должен быть доступным классом и не иметь модификатора final.

    По умолчанию предполагается, что в том случае, если для класса не указано никакого суперкласса, то его непосредственным суперклассом станет класс Object из пакета java.lang, который всегда является корневым классом в любой формируемой иерархии классов.

    Пакеты классов JDK

    Инструментальный набор JDK включает утилиты и пакеты классов.
    Собственно говоря, все стандартные возможности программирования на Java базируются на классах этого инструментального набора. JDK состоит из нескольких отдельных пакетов, иногда называемых библиотеками. Различные среды программирования, такие как JBuilder, предоставляют дополнительные пакеты классов.
    Среда JBuilder 8 Enterprise полностью поддерживает работу со всеми классами пакета JDK 1.4. Пакеты классов JDK

    Приведение ссылочных типов

    В языке Java преобразование ссылочных типов может происходить в четырех контекстах:
  • приведение;
  • присваивание;
  • вызов метода;
  • выполнение арифметических действий.

  • Наиболее общим случаем является приведение.
    В языке Java объявление класса определяет одноименный ссылочный тип. Все переменные, имеющие ссылочный тип, указываемый именем класса, являются объектами. Тип такого объекта определяется оператором instanceof.
    Например:
    String str1; Object ObjectName; ObjectName =(Object) str1; // Приведение типа
    if (ObjectName instanceof String) { // Тип объекта String String str2 = (String) ObjectName ; System.out.println(str2); // Запись в стандартный поток // вывода значения строки, // указанной параметром str2 }
    В рассмотренном примере тип объекта str1 сначала приводится к типу своего косвенного суперкласса Object, а затем оператором instanceof определяется непосредственный тип объекта (при определении оператором instanceof типа объекта ObjectName как String или Object возвращается значение true).
    При приведении ссылочных типов действуют следующие правила:
  • объект всегда может быть приведен к типу своего непосредственного суперкласса;
  • приведение ссылочных типов может выполняться по иерархии классов сколь угодно глубоко;
  • любой класс ссылочного типа всегда можно привести к типу Object.

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

    Например:

    public class A { int x, y; } public class ADerived extends A { int z; } public interface B { void setColor(int color); } public class AB extends A implements B { int color; public void setColor(int color) { this.color = color; } } class MyA{ public static void main(String[ ] args) { // Создание переменных ссылочного типа // и присваивание им значения: A p = new A(); p = new ADerived(); // Правильно: ADerived это // подкласс класса A ADerived p3d = p; // Ошибка

    // Присваивание значения переменной // типа Object: Object o = p; // Правильно: любой объект приводим // к типу Object int[ ] a = new int[3]; Object o2 = a; // Правильно: массив приводим к Object

    // Присваивание значения переменной // типа интерфейса: AB cp = new AB(); B c = cp; // Правильно: AB реализует интерфейс B

    // Присваивание значения переменной // типа массива: byte[ ] b = new byte[4]; a = b; // Ошибка: это массивы различных типов ADerived[ ] p3da = new ADerived[3]; A[ ] pa = p3da; // Правильно: ADerived подкласс класса A p3da = pa; // Ошибка, т.к. необходимо приведение } }

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

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

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

    Раннее и позднее связывание

    Раннее и позднее связывание является одним из проявлений полиморфизма, позволяя выполнять одним оператором вызов различных методов в зависимости от типа объекта.
    В следующем примере оператор b.MyPrint() будет вызывать различные методы в зависимости от типа объекта, для которого он выполняется:
    class B{ void MyPrint () { }} class B1 extends B{ void MyPrint () { //Переопределение метода } } class B2 extends B{ void MyPrint () { //Переопределение метода } } class B3 extends B{ void MyPrint () { //Переопределение метода } } class PrintB{ B DoBObject () { // Метод, реализующий класс B B b; b= new B1(); … b= new B2(); … b= new B3(); … return b; } ... B b= new PrintB.DoBObject(); b.MyPrint() // Выполняет вызов метода MyPrint в // соответствии с типом объекта b

    Вложенные классы

    Проблемы, возникающие из-за отсутствия множественного наследования, частично можно решить с использованием вложенных классов.
    Если требуется, чтобы класс ClassA наследовал все доступные методы, включая и protected-методы, двух классов (класса ClassB и класса ClassC), то реализовать такую схему можно через вложенный класс.
    Класс ClassA создается производным от класса ClassB. Это позволит всем экземплярам класса ClassA вызывать protected-методы класса ClassB.
    В классе ClassA объявляется подкласс ClassFromC, производный от класса ClassC и переопределяющий все protected-методы класса ClassC, реализуя их как вызовы соответствующих методов из суперкласса.
    При такой реализации экземпляр класса ClassA получает доступ к protected-методам двух различных классов - своего суперкласса и своего вложенного класса.

    Введение в программирование

    Конструкторы

    Конструктором называется метод, вызываемый для инициализации объекта при его создании.
    Имя конструктора всегда совпадает с именем класса. Конструктор не может использовать оператор return и для него не указывается никакого типа возвращаемого значения. При объявлении конструктора можно указать модификаторы доступа public, protected или private.
    Наличие явно описанного конструктора в классе не является обязательным. В этом случае при создании объекта используется конструктор по умолчанию. Такой конструктор не получает параметров и вызывает непосредственно конструктор суперкласса: super().
    При этом, если суперкласс не имеет конструктора без списка параметров, то происходит ошибка компиляции.
    Конструкторы не наследуются подклассами.
    Тело конструктора заключается в фигурные скобки.
    При этом первыми операторами должны быть указаны, если они используются, операторы вызова конструкторов данного класса или суперкласса.
    Конструктор может иметь следующее формальное описание:
    ИмяКласса (СписокПараметров) { ВызовКонструкторов БлокОператоров }
    Вызов конструкторов выполняется операторами this и super с указанием в скобках списка параметров.
    Например:
    public class C extends A { public C() {this(1,20); } // Вызов конструктора данного класса public C(int i, int j) { } }
    Вызов конструкторов подчиняется следующим правилам:
  • при создании объекта любого заданного класса будет неявно выполнена цепочка вызовов всех конструкторов его суперклассов;
  • первым будет выполнено тело конструктора для Object;
  • каждый последующий конструктор в цепочке будет выполняться только после выполнения конструктора своего непосредственного суперкласса;
  • при создании объекта будут инициализированы все переменные экземпляра.


  • Объявление переменных

    В языке Java при объявлении переменной - указании ее типа и имени - одновременно можно выполнить ее инициализацию.
    Для переменной могут быть указаны следующие модификаторы доступа:
  • public или protected, или private, - определяющие область видимости переменной;
  • static - указывает, что переменная является переменной класса, а не переменной экземпляра класса;
  • final - запрещает присвоение значений переменной вне тела класса, в котором она объявлена;
  • transient - указывает, что переменная не является частью постоянного состояния объекта;
  • volatile - определяет возможность асинхронного изменения переменной.

  • Переменная, не имеющая модификатора static, называется переменной экземпляра. Переменная экземпляра создается для каждого нового экземпляра класса.
    Переменная, имеющая модификатор static, называется переменной класса. Для всех экземпляров класса существует только одна переменная класса. Эта переменная доступна и до создания экземпляра класса.
    Переменная, имеющая модификатор final, должна быть инициализирована внутри тела класса, так как вне тела класса final-переменная является константой и ее изменение или инициализация запрещены.
    Модификатор transient нельзя использовать совместно с модификаторами final или static.
    Любая переменная может иметь модификатор доступа public (общедоступный), protected (защищенный) или private (скрытый).
    Для этих модификаторов определены следующие правила доступа:
  • public указывает, что данная переменная будет доступна везде, где доступен класс, в котором она объявлена;
  • protected указывает, что данная переменная будет доступна как внутри пакета, содержащего объявление класса, в котором она определена, так и внутри любого подкласса данного класса;
  • private указывает, что данная переменная не будет доступна нигде кроме тела класса, в котором она объявлена.

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

  • Если переменная объявлена с модификатором static, то инициализация выполнятся сразу при загрузке класса.
    Если объявляемая переменная является переменной экземпляра, то инициализация выполняется при выполнении метода-конструктора класса.
    Если объявляемая переменная является локальной переменной, то ее инициализация происходит при выполнении оператора объявления этой переменной.
    Например:
    int i1,i2; float f1 = 3.0; float dArray1 [] = new float [14]; java.lang.String str1 = "no?iea"; Object oObj = str1 ; Exception e = new Exception ( ) ;

    Определение методов

    В языке Java определение метода включает его объявление и реализацию. Определение метода всегда указывается в теле класса.
    Метод может иметь модификаторы доступа, возвращать значение и получать параметры.
    Метод может иметь следующие модификаторы:
  • public, protected или private -модификаторы доступа;
  • static - модификатор метода класса.
  • abstract, final, native или synchronized.

  • Для модификаторов доступа метода определены следующие правила:
  • public указывает, что данный метод будет доступен везде, где доступен класс, в котором он определен;
  • protected указывает, что данный метод будет доступен как внутри пакета, содержащего объявление класса, в котором он определен, так и внутри любого подкласса данного класса;
  • private указывает, что данный метод не будет доступен нигде кроме тела класса, в котором он определен.

  • По умолчанию метод считается доступным везде внутри пакета, содержащего класс, в котором он определен, и недоступным ни в каком другом подклассе указанного класса в том случае, если подкласс содержится в другом пакете.
    Метод, не имеющий модификатора static, называется методом экземпляра. Метод экземпляра может быть вызван только для созданного экземпляра класса или подкласса. Такой метод нельзя вызывать непосредственно, квалифицируя его именем класса.
    Метод, объявленный с модификатором static, называется статическим методом (или методом класса) и может быть вызван без создания экземпляра класса. Этот метод всегда вызывается непосредственно из класса. Статический метод имеет доступ к другим статическим переменным и методам данного класса.
    Если статический метод определен как final-метод, то он не может быть переопределен.
    Например:
    // Файл A.java package classa; public class A implements B { public A() { } static int b=1; public int Metod1(){return a;} public static int Metod2(){ return 0;} //Статический метод } interface B { final public static int a=1; // Статическая переменная int Metod1(); }
    // Файл C.java package classa; public class C extends A { public C() { } static int b=3; public int Metod1(){return a;} public static int Metod2(){return 77;} public static void main(String[] args) { System.out.println(A.Metod2()); System.out.println(C.Metod2()); } }

    При переопределении методов их модификаторы доступа должны совпадать. Так, нельзя переопределить метод, имеющий модификатор доступа public, методом с модификатором доступа private.

    Абстрактный метод указывается модификатором abstract. Такой метод никогда не имеет тела метода: вместо фигурных скобок, ограничивающих тело метода, объявление метода завершается точкой с запятой.

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

    Например:

    public class A extends AA implements B { public A() { } public int Metod1(){return 0;} public static int Metod2(){return 0;} int Metod3(){return 0;} public int Metod4(){return 0;} } interface B { int Metod1(); abstract int Metod4(); } abstract class AA{ abstract int Metod3(); }

    Методы, объявленные с модификатором private, не могут быть абстрактными методами, так как они недоступны вне тела класса. Статические методы также не могут выступать в качестве абстрактных методов, так как считаются конечными и не могут быть переопределены.

    Объявление метода с модификатором final запрещает его последующее переопределение. Такие методы называются конечными методами, и по умолчанию считается, что private-метод всегда является конечным методом.

    Методы, объявленные с модификатором native, могут иметь реализацию на другом языке программирования. Эти методы используются для написания машинно-зависимого кода. native-методы в Java-программе не имеют тела метода.

    Synchronized-методы выполняются с блокировкой:

  • для метода класса выполняется блокировка класса,
  • для метода экземпляра - блокировка объекта.


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

    Метод может возвращать значение заданного типа. В этом случае:

  • перед именем метода указывается тип возвращаемого значения;
  • в теле метода присутствует оператор return, определяющий возвращаемое значение.


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

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

    Передача параметров

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

    Перегружаемые методы

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

    Переопределение метода

    Переопределением метода называется объявление в подклассе метода, у которого имя, тип и список параметров, в точности совпадают с соответствующими атрибутами метода, ранее объявленного в суперклассе.
    При переопределении метода использование модификаторов доступа должно удовлетворять следующим условиям:
  • если переопределяемый метод суперкласса не содержит ни одного из модификаторов доступа public, protected или private, то переопределяющий метод не должен иметь модификатора private.
  • если переопределяемый метод суперкласса имеет модификатор доступа protected, то переопределяющий метод должен иметь модификатор доступа public или protected.
  • если переопределяемый метод суперкласса имеет модификатор доступа public, то переопределяющий метод должен также иметь модификатор доступа public.

  • Тип возвращаемого значения переопределяющего метода должен совпадать или преобразовываться присвоением к типу возвращаемого значения переопределяемого метода.
    Если класс содержит переопределяющий метод, то переопределенный метод можно вызвать только с квалификацией ссылки ключевым словом super или именем суперкласса (для статических членов).
    Например:
    class A { public void Metod1() { } public static void Metod2() { }
    } class B extends A { public Metod1() { } ... Metod1(); // Вызов метода из класса B super.Metod1(); // Вызов метода из класса A A.Metod2(); }

    Создание объекта

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

    Ссылка на текущий объект

    При вызове метода экземпляра ключевое слово this
  • указывает ссылку на текущий объект. Это может быть использовано для передачи самого объекта в качестве аргумента методу самого экземпляра класса;
  • используется для указания квалифицированной ссылки на поля (переменные и методы) экземпляра класса.

  • Ключевое слово super используется для указания квалифицированной ссылки на поля (переменные и методы) суперкласса.
    По умолчанию любой метод первоначально ссылается на свои собственные переменные и методы и только в случае их отсутствия выполняется поиск этих полей вверх по иерархии суперклассов. При этом, если метод не переопределяется, то его имя не обязательно квалифицировать.
    Например:
    class A { public int a; } class B extends A { public int a, b; public void Metod1 ( ) { b=a; // Ссылка на this.a b=super.a; } }
    Имя суперкласса может быть использовано для квалифицированного доступа к статическим переменным или методам.

    Статические переменные

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

  • Инициализация статических переменных выполняется при загрузке класса. Инициализация переменных выполняется в порядке их следования в объявлении класса.
    Например:
    public class C { public C() { } static int b=3; static int c; static { b++; c = 10; } // Инициализация статической переменной }
    При инициализации статических переменных можно вызывать статические методы. Статические переменные

    Введение в программирование

    public static int myPublicInt; internal

    using System; namespace MyNameSpace { public class A { public static int myPublicInt; internal static int myInternalInt; private static int myPrivateInt = 0;

    public class Nest1 // "Вложенный" член класса { public static int myPublicInt; internal static int myInternalInt; private static int myPrivateInt = 0; }

    private class Nest2 // "Вложенный" член класса { public static int myPublicInt = 0; internal static int myInternalInt = 0; private static int myPrivateInt = 0; } } public class MyClass { public static int Main() { // Доступ к членам класса A: A.myPublicInt = 1; // Доступ не ограничен A.myInternalInt = 2; // Только в текущем проекте // A.myPrivateInt = 3; - ошибка: нет // доступа вне класса // Доступ к членам класса Nest1: A.Nest1.myPublicInt = 1; // Доступ не ограничен A.Nest1.myInternalInt = 2; // Только в текущем проекте // A.Nest1.myPrivateInt = 3; - ошибка: нет // доступа вне класса Nest1 // Доступ к членам класса Nest2: // A.Nest2.myPublicInt = 1; - ошибка: нет // доступа вне класса A // A.Nest2.myInternalInt = 2; - ошибка: нет // доступа вне класса A // A.Nest2.myPrivateInt = 3; - ошибка: нет // доступа вне класса Nest2 return 0; } } }

    Листинг 15.1.
    Закрыть окно





    using System;

    namespace MyNameSpace

    {

    public class A

    {

    public static int myPublicInt;

    internal static int myInternalInt;

    private static int myPrivateInt = 0;

    public class Nest1 // "Вложенный" член класса

    {

    public static int myPublicInt;

    internal static int myInternalInt;

    private static int myPrivateInt = 0;

    }

    private class Nest2 // "Вложенный" член класса

    {

    public static int myPublicInt = 0;

    internal static int myInternalInt = 0;

    private static int myPrivateInt = 0;

    }

    }

    public class MyClass

    {

    public static int Main()

    {

    // Доступ к членам класса A:

    A.myPublicInt = 1; // Доступ не ограничен

    A.myInternalInt = 2; // Только в текущем проекте

    // A.myPrivateInt = 3; - ошибка: нет

    // доступа вне класса

    // Доступ к членам класса Nest1:

    A.Nest1.myPublicInt = 1; // Доступ не ограничен

    A.Nest1.myInternalInt = 2; // Только в текущем проекте

    // A.Nest1.myPrivateInt = 3; - ошибка: нет

    // доступа вне класса Nest1

    // Доступ к членам класса Nest2:

    // A.Nest2.myPublicInt = 1; - ошибка: нет

    // доступа вне класса A

    // A.Nest2.myInternalInt = 2; - ошибка: нет

    // доступа вне класса A

    // A.Nest2.myPrivateInt = 3; - ошибка: нет

    // доступа вне класса Nest2

    return 0;

    }

    }

    }

    using System; public class MyClass1

    using System; public class MyClass1 { public static void UseParams1(params int[] list) { // Отображение списка параметров for ( int i = 0 ; i < list.Length ; i++ ) Console.WriteLine(list[i]); } public static void UseParams2(params object[] list) { // В переменном списке параметров могут быть // объекты различных типов for ( int i = 0 ; i < list.Length ; i++ ) Console.WriteLine((object)list[i]); } public static void UseParams3(int k,params object[] list) { // В переменный список параметров // включаются параметры, начиная // со второго for ( int i = 0 ; i < list.Length ; i++ ) Console.WriteLine((object)list[i]); } public static void Main() { UseParams1(1, 2, 3, 4, 5); UseParams1(1, 2); int[] myarray = new int[3] {1,2,3}; UseParams1(myarray); UseParams2(111, 'f', "string"); UseParams3(111, 'f', "string");

    } }

    Листинг 15.2.
    Закрыть окно





    using System;

    public class MyClass1

    {

    public static void UseParams1(params int[] list)

    {

    // Отображение списка параметров

    for ( int i = 0 ; i < list.Length ; i++ )

    Console.WriteLine(list[i]);

    }

    public static void UseParams2(params object[] list)

    { // В переменном списке параметров могут быть

    // объекты различных типов

    for ( int i = 0 ; i < list.Length ; i++ )

    Console.WriteLine((object)list[i]);

    }

    public static void UseParams3(int k,params object[] list)

    { // В переменный список параметров

    // включаются параметры, начиная

    // со второго

    for ( int i = 0 ; i < list.Length ; i++ )

    Console.WriteLine((object)list[i]);

    }

    public static void Main()

    {

    UseParams1(1, 2, 3, 4, 5);

    UseParams1(1, 2);

    int[] myarray = new int[3] {1,2,3};

    UseParams1(myarray);

    UseParams2(111, 'f', "string");

    UseParams3(111, 'f', "string");

    }

    }

    Данный пример иллюстрирует консольное приложение,

    /* Данный пример иллюстрирует консольное приложение, позволяющее добавлять и отображать элементы структуры. Используемый массив myAB содержит 400 элементов, каждый из которых является структурой из двух полей - name и telfax*/ using System; namespace MyStruct1 { struct AddrBookType { public string name; public string telfax ; } /* Созданная структура определяет новый структурный тип AddrBookType. Элементы структуры объявлены с модификаторами доступа public, так как по умолчанию элементы доступны только внутри структуры */ class Class1 { static void Main(string[] args) { // Создание массива структур AddrBookType[] myAB= new AddrBookType[400]; char icount; char iloop; int i=0; int j=0; while (true) // Запрос кода операции {Console.Write ("Insert kod (0 - new record, 1 - show all, 2 - exit): "); icount = (char)Console.Read (); while (true) // Чтение потока ввода { iloop = (char)Console.Read (); /* Цикл чтения символов будет завершен при нажатии пользователем клавиши Enter и получения из потока ввода символа '\n' */ if (iloop == '\n') break;} if (icount=='2') break; switch (icount) {case '0': Console.WriteLine("Insert Name: "); myAB[i].name =Console.ReadLine (); Console.WriteLine("Insert phone : "); myAB[i].telfax= Console.ReadLine (); i++; // Счетчик введенных элементов break; case '1': // Запись в стандартный поток // вывода for ( j=0; j
    Листинг 15.3.
    Закрыть окно





    /* Данный пример иллюстрирует консольное приложение, позволяющее добавлять и отображать элементы структуры. Используемый массив myAB содержит 400 элементов, каждый из которых является структурой из двух полей - name и telfax*/

    using System;

    namespace MyStruct1

    {

    struct AddrBookType

    { public string name;

    public string telfax ;

    }

    /* Созданная структура определяет новый структурный тип AddrBookType. Элементы структуры объявлены с модификаторами доступа public, так как по умолчанию элементы доступны только внутри структуры */

    class Class1

    {

    static void Main(string[] args)

    { // Создание массива структур

    AddrBookType[] myAB= new AddrBookType[400];

    char icount;

    char iloop;

    int i=0;

    int j=0;

    while (true) // Запрос кода операции

    {Console.Write ("Insert kod (0 - new record,

    1 - show all, 2 - exit): ");

    icount = (char)Console.Read ();

    while (true) // Чтение потока ввода

    { iloop = (char)Console.Read ();

    /* Цикл чтения символов будет завершен при

    нажатии пользователем клавиши Enter и

    получения из потока ввода символа '\n' */

    if (iloop == '\n') break;}

    if (icount=='2') break;

    switch (icount)

    {case '0':

    Console.WriteLine("Insert Name: ");

    myAB[i].name =Console.ReadLine ();

    Console.WriteLine("Insert phone : ");

    myAB[i].telfax= Console.ReadLine ();

    i++; // Счетчик введенных элементов

    break;

    case '1': // Запись в стандартный поток

    // вывода

    for ( j=0; j

    {Console.Write(myAB[j].name);

    Console.Write(" ");

    Console.WriteLine(myAB[j].telfax); }

    break;

    default :

    Console.WriteLine("Ошибка ввода");

    break;

    } // Конец switch

    } // Конец while

    }

    } }

    Явный вызов конструктора

    Определение конструктора может содержать явный вызов конструктора того же класса. Вызываемый конструктор указывается после имени определяемого конструктора со списком параметров через символ двоеточия. Вызываемый конструктор может быть определен ключевым словом this - для вызова конструктора из того же самого класса, или ключевым словом base - для вызова конструктора базового класса. Явно вызываемый конструктор будет выполнен до выполнения конструктора, в котором он указывается.
    Например:
    public class A { public A():this(222) // Конструктор без параметров { } public A(int i) // Конструктор с одним параметром { } }

    Комментарии в программе на языке C#

    Комментарий в языке С# может быть как однострочным, так и многострочным.
    Однострочный комментарий может размещаться в начале строки или после некоторого кода. Он начинается символами // и завершается концом строки.
    Многострочный комментарий располагается между парами символов /* и */ .
    Комментарий, вставляемый средой проектирования, например // TODO: Add code to start application here указывает место, в которое должен быть вставлен код, выполняемый при запуске приложения.
    Существует особый тип комментария, который записывается в summary-секции:
    /// - /// .
    Такой комментарий может быть использован для автоматического документирования приложения.
    При автоматическом документировании приложения создается XML-файл, представляющий собой информацию о приложении как некоторую иерархию секций. Для того чтобы при компиляции приложения создавался XML-файл документа, следует установить опции компиляции следующим образом: в окне Solution Explorer выделить секцию с именем проекта и выполнить команду меню View|Property Pages (или Shift+F4), а затем, выбрав папку Configuration Properties и страницу свойств Build, установить новое значение свойства XML Documentation File, описывающее имя файла, в котором будет сохранен XML-документ.

    Методы члены класса

    Среда проектирования Visual Studio .NET дает возможность использовать мастер создания метода - члена класса (в окне Class View выбрать имя класса и выполнить команду контекстного меню Add|Add Metod). Список Modifier. диалога. C# Metod Wizard позволяет указать один из следующих модификаторов параметра метода:
  • none - определяет передачу параметров по значению. Если внутри метода будет изменено значение фактического параметра, то вне метода его значение останется прежним;
  • ref - определяет передачу параметров по ссылке. Изменение параметра внутри метода останется и после завершения метода. ref-параметр перед использованием обязательно должен быть инициализирован;
  • out - определяет передачу параметров по результату. При завершении метода конечное значение формального параметра присваивается указанному при вызове фактическому параметру. При этом в момент вызова метода фактический параметр может не быть инициализирован.

  • Например:
    public void Metod1(int i, ref int j, out int k) { }
    При обращении к методу или полю - членам класса используется операция . (точка) - доступ к члену класса. Имя поля или метода члена класса квалифицируется именем экземпляра класса.
    Язык C# позволяет использовать методы с переменным числом параметров. Для метода с переменным числом параметров должны быть выполнены следующие правила:
  • переменный список параметров выступает как единый параметр и указывается ключевым словом params;
  • кроме переменного списка параметров, никаких других параметров после ключевого слова params в методе указывать нельзя;
  • в методе может быть указано только одно ключевое слово params, определяющее переменный список параметров.

  • Количество параметров в переменном списке параметров определяется свойством Length .
    Например:
    using System; public class MyClass1 { public static void UseParams1(params int[] list) { // Отображение списка параметров for ( int i = 0 ; i < list.Length ; i++ ) Console.WriteLine(list[i]); } public static void UseParams2(params object[] list) { // В переменном списке параметров могут быть // объекты различных типов for ( int i = 0 ; i < list.Length ; i++ ) Console.WriteLine((object)list[i]); } public static void UseParams3(int k,params object[] list) { // В переменный список параметров // включаются параметры, начиная // со второго for ( int i = 0 ; i < list.Length ; i++ ) Console.WriteLine((object)list[i]); } public static void Main() { UseParams1(1, 2, 3, 4, 5); UseParams1(1, 2); int[] myarray = new int[3] {1,2,3}; UseParams1(myarray); UseParams2(111, 'f', "string"); UseParams3(111, 'f', "string");
    } }
    Листинг 15.2.

    Модификаторы доступа

    В языке C# применяются следующие модификаторы доступа:
  • public - доступ не ограничен;
  • protected - доступ ограничен только наследуемыми классами;
  • internal - доступ ограничен рамками текущего проекта;
  • private - доступ ограничен рамками данного класса.

  • Для любого члена класса или объектного типа разрешено указывать только один модификатор доступа, за исключением комбинации protected internal, регламентирующей ограничение доступа наследуемыми классами текущего проекта.
    Например:
    class A { protected int x = 100; }
    class B : A { void M1() { A a1 = new A(); // Создание объекта типа A B b1 = new B(); // Создание объекта типа B // a1.x = 200; - доступ не разрешен b1.x = 200; // Правильно реализованный доступ } }
    Отметим, что пространство имен не может иметь модификатора доступа.
    Язык C# поддерживает использование вложенных классов.
    Типы верхнего уровня, которые не являются вложенными в другие типы, могут иметь модификатор доступа только internal (по умолчанию) или public.
    Если модификатор доступа не указан, то применяется доступ по умолчанию. В следующей таблице отображены модификаторы доступа для вложенных типов, являющихся членами других типов.
    Член, определяемый в:Модификатор доступа,используемый по умолчаниюДопустимые модификаторы доступа,используемые для членов
    enum Public -
    class private public protected internal private protected internal
    interface public -
    struct private public internal private
    Структуры не могут иметь модификатор доступа protected,так как не могут быть наследуемы

    Например:
    using System; namespace MyNameSpace { public class A { public static int myPublicInt; internal static int myInternalInt; private static int myPrivateInt = 0;
    public class Nest1 // "Вложенный" член класса { public static int myPublicInt; internal static int myInternalInt; private static int myPrivateInt = 0; }
    private class Nest2 // "Вложенный" член класса { public static int myPublicInt = 0; internal static int myInternalInt = 0; private static int myPrivateInt = 0; } } public class MyClass { public static int Main() { // Доступ к членам класса A: A.myPublicInt = 1; // Доступ не ограничен A.myInternalInt = 2; // Только в текущем проекте // A.myPrivateInt = 3; - ошибка: нет // доступа вне класса // Доступ к членам класса Nest1: A.Nest1.myPublicInt = 1; // Доступ не ограничен A.Nest1.myInternalInt = 2; // Только в текущем проекте // A.Nest1.myPrivateInt = 3; - ошибка: нет // доступа вне класса Nest1 // Доступ к членам класса Nest2: // A.Nest2.myPublicInt = 1; - ошибка: нет // доступа вне класса A // A.Nest2.myInternalInt = 2; - ошибка: нет // доступа вне класса A // A.Nest2.myPrivateInt = 3; - ошибка: нет // доступа вне класса Nest2 return 0; } } }
    Листинг 15.1.

    Объявление класса

    В языке С# определение класса не обязательно должно иметь методы конструктор и деструктор.
    Управляемый код на языке С# избавлен от необходимости освобождения памяти, выделяемой под объекты, так как это реализуется средой NET Framework. Поэтому основное назначение деструктора в языке C# - это освобождение неуправляемых ресурсов, таких как окна, файлы, сетевые соединения и т.п.
    Язык C# поддерживает три типа конструкторов:
  • конструктор экземпляра объекта ( instance), используемый при создании объекта;
  • private-конструктор, указываемый в коде для предотвращения автоматического создания конструктора по умолчанию. Такой тип конструктора используется для классов, имеющих только статические члены. Экземпляр объекта с private-конструктором не может быть создан.
  • статический конструктор ( static), вызываемый для инициализации класса до создания первого объекта или до первого вызова статического метода. Статический конструктор не может иметь модификаторы доступа и список параметров.

  • Конструктор экземпляра объекта имеет следующее формальное описание:
    [атрибуты] [модификаторы_доступа] имя_конструктора([список_формальных_параметров]) [:base (список_аргументов) | :this (список_аргументов)] { тело_конструктора }
    Ключевое слово base определяет явный вызов конструктора базового класса, а ключевое слово this - вызов конструктора данного класса с указанным списком параметров.
    Например:
    public class AClass1 { public AClass1()// Объявление конструктора { } }
    Ключевое слово class определяет имя объявляемого класса. Тело объявляемого класса указывается в фигурных скобках.
    Ключевое слово public - это модификатор доступа, указывающий, что объявляемые после него идентификаторы (имена классов или методов) будут общедоступны (модификатор доступа позволяет определить область видимости переменных и методов - членов класса).
    По умолчанию все переменные и методы - члены класса, заданные без модификатора доступа, считаются private-переменными (называемыми иногда приватными или закрытыми). Приватные переменные доступны только внутри экземпляра класса и не могут быть использованы во внешних функциях модуля.

    Пространство имен System

    Библиотека классов .NET Framework среды Visual Studio.NET состоит из иерархически организованного набора пространства имен. В каждом пространстве имен определяется набор типов (классы, структуры, нумераторы, интерфейсы). Пространство имен System содержит набор классов для общеиспользуемых значений и ссылочных типов данных, событий и обработчиков событий, интерфейсов, атрибутов и т.п. Также это пространство имен содержит классы, позволяющие выполнять преобразование типов, реализовывать операции ввода/вывода и т.п.
    Все встроенные типы данных языка C# реализованы как классы пространства имен. Пространство имен System включает такие классы, как Console, String, Array, Math, Boolean, Byte, Char, DateTime, Decimal, Double, Int16, Int32, Voidи т.п.
    Псевдонимы типов языка C# и соответствующие им предопределенные типы пространства имен являются при написании программы взаимозаменяемыми.
    Для определения типа переменной можно использовать метод GetType или оператор typeof.
    Библиотека классов NET Framework предоставляет для реализации потоков ввода, вывода и ошибок класс Console, располагаемый в пространстве имен System.
    Класс Console имеет следующие свойства, описывающие соответствующие потоки ввода/вывода:
  • In - стандартный поток ввода;
  • Out - стандартный поток вывода;
  • Error - стандартный поток вывода ошибок.

  • Класс Console содержит следующие методы, позволяющие осуществлять чтение и запись символов из потоков ввода/вывода:
  • Read - чтение символов из потока ввода;
  • ReadLine - чтение строки символов из потока ввода;
  • Write - запись строки символов в поток вывода;
  • WriteLine - запись в поток вывода строки символа, ограниченной символами конца строки.

  • Работа с различными видами коллекций реализуется такими классами пространства имен System.Collections , как:
  • ArrayList - динамически расширяемый массив;
  • BitArray - структура данных, каждый элемент которой реализуется как битовое значение;
  • Hashtable - коллекция связанных ключей и значений;
  • SortedList - массив, состоящий из пар "ключ-значение";
  • Queue - очередь;
  • Stack - коллекция объектов, реализуемая как стек.


  • Пространство имен

    Пространство имен позволяет именовать группу данных, таких как классы, переменные и/или методы. В языке C# все библиотеки классов подключаются как пространства имен.
    При автоматическом формировании проекта в среде Visual Studio.NET первой строкой создаваемого приложения вставляется строка using System.
    Ключевое слово using подключает библиотеку классов System (каждая библиотека классов рассматривается как пространство имен).
    Создание пространства имен указывается ключевым словом namespace.
    Объявляемые пространства имен могут использоваться для структурирования программы.
    Например:
    namespace NameSN1.NameSN2 { class A {} } namespace NameSN3 { using NameSN1.NameSN2; class B: A {} }
    В среде проектирования Visual Studio.NET библиотеки классов NET Framework образуют иерархическую структуру пространств имен.
    Библиотеку классов среды .NET Framework иногда называют NET Framework-библиотекой или просто Framework-библиотекой.
    Объявление пространства имен имеет следующее формальное описание:
    namespace name[.name1] ...] { // объявляемые_данные }
    Пространство имен указывается идентификатором, который может содержать операцию . , определяющую составное имя пространства имен.
    Объявляемыми данными пространства имен могут быть:
  • другие пространства имен;
  • классы;
  • интерфейсы;
  • структуры;
  • перечисления.

  • Для того чтобы иметь возможность обращаться к переменным или методам из пространства имен, можно использовать один из следующих способов:
  • имя соответствующей переменной или метода должно быть квалифицировано названием пространства имен (пространство имен указывается перед именем через точку).
    Например:
    System.Console.WriteLine("Печать строки");
  • имя библиотеки должно быть установлено как доступное оператором using.
    Например:
    using System;

  • Директива using может использоваться для:
  • подключения пространства имен. Класс не может быть подключен директивой using;
  • создания псевдонима имени класса. Псевдоним используется в программе для квалификации членов данного класса.

  • Объявление псевдонима имеет следующее формальное описание:
    using alias=class_name;
    Например:
    using System.Console = my_SN; class MyClass { public static void Main() { my_SN.WriteLine("123");} }
    Директива using позволяет не квалифицировать каждую переменную пространством имен, а просто подключить требуемое пространство имен.

    Создание экземпляра класса

    Для использования переменных или методов класса следует создать объект - экземпляр класса.
    В языке C# экземпляр класса всегда создается при помощи оператора new. Если класс имеет несколько конструкторов, то при создании переменной указывается требуемый конструктор.
    Место выделения памяти под объект зависит от типа создаваемого объекта: объекты ссылочных типов размещаются в куче, а объекты размерных типов - в стеке.
    Объявление переменной объектного типа в языке С# не создает объекта, а только определяет идентификатор указанного типа. Обратите внимание, что во многих объектно-ориентированных языках, таких как С++, объявление переменной объектного типа также становится и созданием экземпляра данного типа.
    Например:
    using System; namespace MyNS { public class A { public A() // Конструктор без параметров { Console.WriteLine("A()"); } public A(int i) // Конструктор с одним параметром { Console.Write("A(i) i= "); Console.WriteLine(i); } } } using System; namespace MyNS { class MyClass { static void Main(string[] args) { A acl1= new A(); // Создание экземпляра класса A acl2= new A(987); } } }

    Структура приложения на языке С#

    Проектом называется совокупность файлов, содержащих информацию об установках, конфигурации, ресурсах проекта, а также файлов исходного кода и заголовочных файлов.
    Интегрированная среда проектирования VisualStudio.NET позволяет для создания проектов на разных языках программирования использовать различные инструментальные средства проектирования (например, Microsoft Visual Basic, Microsoft Visual C#).
    Любое приложение на языке C#, разрабатываемое в среде проектирования VisualStudio.NET, реализуется как отдельный проект. Приложение на языке С# может состоять из нескольких модулей. Каждый модуль C# может содержать код нескольких классов (при создании приложения в среде Visual Studio.NET каждый класс C# автоматически помещается в отдельный модудь - файл с расщирением cs). Среда Visual Studio 2005 позволяет создавать частичные классы ( partial class), когда один класс содержится в нескольких файлах. Соединение всех частей класса выполняется на этапе компиляции. (Вообще, частичными также могут быть структуры и интерфейсы.)
    Для консольного приложения один из классов, реализуемых модулем, должен содержать метод Main. В языке C# нет аппарата заголовочных файлов, используемого в языке С++, поэтому код модуля должен содержать как объявление, так и реализацию класса.
    По умолчанию весь код класса, представляющего консольное приложение, заключается в одно пространство имен, одноименное с именем приложения.
    Точкой входа в программу на языке C# является метод Main.
    Этот метод может записываться как без параметров, так и с одним параметром типа string. - указателем на массив строк, который содержит значения параметров, введенных при запуске программы. В отличие от списка параметров, задаваемых при запуске С-приложения, список параметров C#-приложения не содержит в качестве первого параметра имя самого приложения.
    Код метода указывается внутри фигурных скобок:
    static void Main(string[] args) { }
    Ключевое слово static определяет, что метод Main является статическим методом, вызываемым без создания экземпляра объекта типа класса, в котором этот метод определен.

    Метод, не возвращающий никакого значения, указывается с ключевым словом void. Однако, метод Main может возвращать значение типа int.

    Например:

    static int Main(string[] args) { // Проверка числа введенных параметров if (args.Length == 0) { Console.WriteLine("Нет параметров"); return 1; } // Для получения значения параметра как значения типа long // используется функция Parse long num = Int64.Parse(args[0]); // Тип long языка C# является псевдонимом типа Int64. // Поэтому предыдущая запись эквивалентна записи // long num = long.Parse(args[0]); // Для получения значения параметра как значения // определенного типа также можно использовать // метод ToInt64 класса Convert long num = Convert.ToInt64(s); }

    Компилятор C# допускает наличие метода Main сразу в нескольких классах. Но для успешной компиляции и выполнения такого приложения следует указать класс, метод Main которого следует считать точкой входа в приложение. Это можно сделать, установив опции проекта или указав опцию компилятора /main с именем класса, чей метод Main будет задействован (например: csc class1.cs class2.cs /main:Class2).

    Для того чтобы установить опцию проекта, определяющую "стартовый" класс (Startup Object), следует открыть диалог свойств проекта Property Pages, в секции Common Properties на странице General выбрать опцию Startup Object и указать для нее имя "стартового" класса (рис. 1).

    Структура приложения на языке С#
    Рис. 15.1.  Определение имени "стартового класса"

    Структуры

    Структуры языка C# идентичны классам и представляют поименованную совокупность компонент, называемых членами или элементами структуры. Элементом структуры может быть переменная любого допустимого типа или функция.
    Однако структура относится к размерному типу, а класс - к ссылочному типу. Под структуру выделяется память, достаточная для размещения всех элементов структуры.
    При создании массивов применение типа структуры бывает более эффективно, чем применение типа класса.
    Тип struct является размерным типом, который может содержать конструкторы, константы, поля, методы, свойства, индексаторы, операторы и вложенные типы.
    Объявление структуры может иметь следующее формальное описание (необязательные элементы указаны в квадратных скобках):
    [атрибуты] ]модификаторы] struct имя_структуры [:интерфейсы] { конструктор () {} тип_элемента_структуры имя_ элемента1; тип_элемента_структуры имя_ элемента2; ... тип_элемента_структуры имя_ элементаN; } [ ;] // имя_элемента может быть именем переменной или именем функции
    Для обращения к отдельным элементам структуры используется оператор . (точка).
    Доступ к элементам структуры может иметь следующее формальное описание:
    struct имя_структуры { модификатор тип_элемента элемент_структуры1; модификатор тип_элемента элемент_структуры2; } // Объявление переменной типа структуры имя_структуры имя_переменной_структуры1; имя_структуры [] имя_переменной_структуры2 = new имя_структуры[размерность]; // Доступ к элементу структуры имя_переменной_структуры1.элемент_структуры1= значение1; имя_переменной_структуры2[индекс].элемент_структуры1=значение2;
    Например:
    /* Данный пример иллюстрирует консольное приложение, позволяющее добавлять и отображать элементы структуры. Используемый массив myAB содержит 400 элементов, каждый из которых является структурой из двух полей - name и telfax*/ using System; namespace MyStruct1 { struct AddrBookType { public string name; public string telfax ; } /* Созданная структура определяет новый структурный тип AddrBookType. Элементы структуры объявлены с модификаторами доступа public, так как по умолчанию элементы доступны только внутри структуры */ class Class1 { static void Main(string[] args) { // Создание массива структур AddrBookType[] myAB= new AddrBookType[400]; char icount; char iloop; int i=0; int j=0; while (true) // Запрос кода операции {Console.Write ("Insert kod (0 - new record, 1 - show all, 2 - exit): "); icount = (char)Console.Read (); while (true) // Чтение потока ввода { iloop = (char)Console.Read (); /* Цикл чтения символов будет завершен при нажатии пользователем клавиши Enter и получения из потока ввода символа '\n' */ if (iloop == '\n') break;} if (icount=='2') break; switch (icount) {case '0': Console.WriteLine("Insert Name: "); myAB[i].name =Console.ReadLine (); Console.WriteLine("Insert phone : "); myAB[i].telfax= Console.ReadLine (); i++; // Счетчик введенных элементов break; case '1': // Запись в стандартный поток // вывода for ( j=0; j Листинг 15.3.
    Язык C# позволяет создавать переменные типы структуры двумя способами:
  • традиционным способом с применением оператора new- в этом случае объявление переменной типа структуры идентично объявлению переменной типа класса и при объявлении переменной возможна одновременная инициализация полей структуры;
  • обычным объявлением переменной как для любого размерного типа.

  • Структуры

    Управляемый код

    Язык программирования C# был разработан как язык, использующий технологию .NET. Поэтому приложение на C# компилируется в промежуточный код, называемый IL-кодом (Intermediate Language) или MSIL-кодом (Microsoft intermediate language). Такой код перед выполнением компилируется JIT-компилятором в команды, отвечающие специфике конкретного процессора.
    Выполнение IL-кода управляется механизмом CLR (Common Language Runtime), непосредственно осуществляющим JIT-компиляцию (Just In Time), наложение политик безопасности, предоставление отладочных сервисов, автоматическое управление памятью (реализация механизма "сборки мусора"). IL-код можно компилировать как при установке приложения, так и при его выполнении (при этом компилироваться будет не весь код, а только реально вызываемые методы). В процессе компиляции кроме IL-кода формируются также метаданные, описывающие классы. CLR использует метаданные для поиска и загрузки классов, размещения объектов в памяти, определения входящих в класс методов и свойств. CLR можно рассматривать как некоторую виртуальную машину, выполняющую приложения .NET. Среда CLR обеспечивает единообразное поведение всех приложений вне зависимости от языка реализации кода. CLS-спецификация (Common Language Specification) определяет требования к CLS-совместимым языкам программирования, использующим классы .NET Framework как некоторую унифицированную систему типов.
    Кроме создания MSIL-кода, CLS-совместимый компилятор добавляет в выходной EXE-файл метаданные, описывающие используемые типы и методы. Под метаданными понимаются некоторые данные, которые описывают другие данные. Используя метаданные, среда CLR определяет требуемые во время выполнения типы и методы.
    Библиотеки классов .NET Framework предоставляют большой набор методов отражения, применяемых средой CLS и другими приложениями для получения информации о типах и методах, реализуемых приложением. Отражением называется механизм получения метаданных. АPI отражения среды .NET представляет собой иерархию классов System.Reflection.
    .NET Framework - это та часть платформы .NET, которая предназначена для создания надежных, масштабируемых и распределенных приложений, использующих технологии .NET.
    .NET Framework состоит из CLR (Common Language Runtime) - среды времени выполнения кода, и из набора библиотек классов (иногда называемых BCL - Base Class Library).
    Приложения, выполняемые под управлением CLR, называются управляемым кодом.
    В Windows выполняемым приложением является EXE-файл, библиотеки реализуются как DLL-файлы. Технология .NET предоставляет приложения в виде сборок, описывающих "логические" EXE- или DLL- файлы. Сборка содержит декларацию, которая описывает ее содержимое. Так, сборка mscorlib.dll содержит все стандартные пространства имен из пространства имен System для .NET.

    Введение в программирование

    Абстрактные классы

    Абстрактным классом называется класс, который содержит один или несколько абстрактных методов.
    Абстрактный класс не может использоваться для создания объектов.
    Как правило, абстрактный класс описывает некий интерфейс, который должен быть реализован всеми его производными классами.
    Абстрактный метод языка C# не имеет тела метода и аналогичен чисто виртуальному методу языка C++.
    Например:
    public abstract int M1(int a, int b);
    Абстрактный класс можно использовать только как базовый для других классов. При этом если производный класс не содержит реализации абстрактного метода, то он также является абстрактным классом.
    По умолчанию при создании абстрактного класса в среде VisualStudio .NET в формируемый абстрактный класс автоматически вставляется только один метод - конструктор без параметров.

    и тип ссылки совпадают CA

    using System; namespace MyDerriv1 { class Class1 { static void Main(string[] args) { // Тип объекта и тип ссылки совпадают CA var1; var1=new CA(); // Вызывается метод класса CA Console.WriteLine (var1.F1()); // Вызывается метод класса CA Console.WriteLine (var1.F2()); // Тип объекта - CB , а тип ссылки - CA CA var2; var2=new CB(); // Вызывается метод класса CA Console.WriteLine (var2.F1()); // Вызывается метод класса CB Console.WriteLine (var2.F2()); } } } // Класс CA using System; namespace MyDerriv1 { public class CA { public CA() { } public int F1() { return 1; } public virtual string F2() {return "Метод F2 класса CA";} } } // Класс CB using System; namespace MyDerriv1 { public class CB : MyDerriv1.CA { public CB() { } public int F1() {return 2; } // Переопределение виртуального метода F2 public override string F2() { return "Метод F2 класса CB"; } } }
    Листинг 16.1.
    Закрыть окно





    using System;

    namespace MyDerriv1

    {

    class Class1

    {

    static void Main(string[] args)

    {

    // Тип объекта и тип ссылки совпадают

    CA var1; var1=new CA();

    // Вызывается метод класса CA

    Console.WriteLine (var1.F1());

    // Вызывается метод класса CA

    Console.WriteLine (var1.F2());

    // Тип объекта - CB , а тип ссылки - CA

    CA var2; var2=new CB();

    // Вызывается метод класса CA

    Console.WriteLine (var2.F1());

    // Вызывается метод класса CB

    Console.WriteLine (var2.F2());

    }

    }

    }

    // Класс CA

    using System;

    namespace MyDerriv1

    {

    public class CA

    { public CA() { }

    public int F1() { return 1; }

    public virtual string F2()

    {return "Метод F2 класса CA";}

    }

    }

    // Класс CB

    using System;

    namespace MyDerriv1

    { public class CB : MyDerriv1.CA

    {

    public CB() { }

    public int F1() {return 2; }

    // Переопределение виртуального метода F2

    public override string F2()

    { return "Метод F2 класса CB"; }

    }

    }

    определяющий однопотоковую модель static void

    using System; namespace MyAClass1 { class Class1 {[STAThread] // Класс // System.STAThreadAttribute, // определяющий однопотоковую модель static void Main(string[] args) { CB varb1 = new CB(); /* Запрос о совместимости типа объекта с типом наследуемого им интерфейса */ if (varb1 is IA) /* Если переменная типа CB является переменной типа класса, реализующего запрашиваемый интерфейс IA, то оператор is вернет значение true. */ {Console.WriteLine ("varb1 - это ссылка на класс, который реализует интерфейс IA");} // Создание объекта типа интерфейса IA IA ivar=(IA)varb1; if (ivar is IA) {Console.WriteLine ("ivar - это ссылка на интерфейс IA");} bool var1=ivar.F1(); Console.WriteLine("Вызов метода F1 интерфейса IA: {0}",var1); // Приведение объекта к типу интерфейса Object ivar1 = varb1 as IA; if (ivar1 != null) Console.WriteLine ( "ivar1 - это ссылка на интерфейс IA"); } } } using System; namespace MyAClass1 { public class CB : MyAClass1.CA,IA {public CB() { } public bool F1() { return true; } public int F2(int a) { return a*10; } } interface IA { bool F1();} } using System; namespace MyAClass1 { public abstract class CA { public CA() { } public abstract int F2(int a); } }
    Листинг 16.2.
    Закрыть окно





    using System;

    namespace MyAClass1

    { class Class1

    {[STAThread] // Класс

    // System.STAThreadAttribute,

    // определяющий однопотоковую модель

    static void Main(string[] args)

    {

    CB varb1 = new CB();

    /* Запрос о совместимости типа объекта с типом наследуемого им интерфейса */

    if (varb1 is IA)

    /* Если переменная типа CB является переменной типа класса, реализующего запрашиваемый интерфейс IA, то оператор is вернет значение true. */

    {Console.WriteLine ("varb1 - это ссылка на

    класс, который реализует интерфейс IA");}

    // Создание объекта типа интерфейса IA

    IA ivar=(IA)varb1;

    if (ivar is IA)

    {Console.WriteLine ("ivar - это ссылка на интерфейс IA");}

    bool var1=ivar.F1();

    Console.WriteLine("Вызов метода F1 интерфейса IA: {0}",var1);

    // Приведение объекта к типу интерфейса

    Object ivar1 = varb1 as IA;

    if (ivar1 != null)

    Console.WriteLine ( "ivar1 - это ссылка на

    интерфейс IA");

    }

    }

    }

    using System;

    namespace MyAClass1

    {

    public class CB : MyAClass1.CA,IA

    {public CB() { }

    public bool F1() { return true; }

    public int F2(int a) { return a*10; }

    }

    interface IA { bool F1();}

    }

    using System;

    namespace MyAClass1

    { public abstract class CA

    { public CA() { }

    public abstract int F2(int a);

    }

    }

    Механизмы наследования

    Объявление класса в языке C# создает новый ссылочный тип, определяющий как описание методов, так и их реализацию.
    Объявление интерфейса создает новый ссылочный тип, который специфицирует описание методов и имена некоторых констант, но не определяет саму реализацию.
    Интерфейс может быть объявлен для расширения одного или нескольких интерфейсов.
    Наследование позволяет определять новые классы в терминах существующих классов. В языке C# поддерживается только простое наследование: любой подкласс является производным только от одного непосредственного суперкласса. При этом любой класс может наследоваться от нескольких интерфейсов.

    Методы - члены класса

    В среде VisualStudio.NET добавить в класс новый метод можно, используя контекстное меню окна Class View. На рис. 16.2 приведен диалог C# MetodWizard, позволяющий определить модификаторы метода и список формальных параметров.
    Методы - члены класса
    Рис. 16.2.  Диалог C# MetodWizard
    Язык C# поддерживает следующие модификаторы метода члена класса:
  • static - определяет статический метод, доступный без создания экземпляра класса;
  • abstract - определяет абстрактный метод, который является членом абстрактного класса;
  • virtual - метод, реализация которого может быть переопределена в производных классах;
  • extern - метод, имеющий реализацию вне данного класса (внешний метод);
  • override- метод, выполняющий переопределение виртуальной функции, наследуемой от базового класса;
  • new - метод, скрывающий в производном классе наследуемый метод с тем же именем (если ключевое слово не указано, то имя скрывается, но при компиляции отображается предупреждение warning).

  • Порядок указания модификаторов доступа и модификаторов метода несущественен.
    Виртуальные и абстрактные методы всегда должны указываться с модификатором доступа public.

    Определение интерфейса

    В языке C# отсутствует множественное наследование: каждый класс может иметь только один непосредственный базовый класс. Частичной заменой множественному наследованию может служить использование интерфейсов.
    Интерфейсы могут содержать свойства, методы и индексаторы, но без их реализации.
    Один класс языка C# может наследовать несколько интерфейсов.
    В C# интерфейс определяет новый ссылочный тип, содержащий объявления методов, которые обязательно должны быть реализованы в классе, наследующем данный интерфейс.
    Можно сказать, что интерфейс определяет некоторую модель поведения, которая должна быть реализована в любом классе, наследующем данный интерфейс.
    Объявление интерфейса может иметь следующее формальное описание:
    [атрибуты] [модификаторы] interface имя_интерфейса [:список_базовых_интерфейсов] {тело_интерфейса}[;]
    Например:
    interface IMyInterface: IBase1, IBase2 { int M1(); int M2(); }
    Если класс, наследующий интерфейс, не является абстрактным, то он обязательно должен реализовать методы, объявленные в интерфейсе. При наследовании интерфейса абстрактным классом методы, объявленные в интерфейсе, могут не иметь реализации только в том случае, если они объявляются с модификатором abstract.
    Например:
    public abstract class CMyInterface : IMyInterface { public CMyInterface() { // } public abstract int M1(); public abstract int M2(); } interface IMyInterface { int M1(); int M2(); }

    Определение типа объекта

    Для получения информации о том, является ли тип объекта времени выполнения совместимым с заданным типом, используется оператор is. Если типы совместимы, то оператор возвращает значение true.
    Оператор as аналогичен оператору is, с той лишь разницей, что выполняет приведение в случае совместимости типов или устанавливает ссылку на несовместимый объект равной null.
    Применение оператора is имеет следующее формальное описание:
    выражение is тип
    Например:
    string str1 = myObjects; if (str1 is string) Console.WriteLine ("тип string");
    Применение оператора as имеет следующее формальное описание:
    выражение as тип
    Например:
    string str1 = myObjects as string; if (str1 != null) Console.WriteLine ( "это строка" );
    При этом предыдущая форма записи эквивалентна следующей записи:
    выражение as тип ? (тип)выражение : (тип)null

    Приведение типа объекта к типу интерфейса

    При создании объект сразу можно приводить к типу интерфейса, используя оператор as
    Например:
    Object ivar1 = varb1 as IA;
    Если приведение допустимо, то переменная будет содержать ссылку на интерфейс. Если приведение типа объекта типу интерфейса недопустимо, то в результате приведения типа переменная примет значение null.
    Следующий пример иллюстрирует определение типов объектов и приведение типа объекта к типу интерфейса.
    using System; namespace MyAClass1 { class Class1 {[STAThread] // Класс // System.STAThreadAttribute, // определяющий однопотоковую модель static void Main(string[] args) { CB varb1 = new CB(); /* Запрос о совместимости типа объекта с типом наследуемого им интерфейса */ if (varb1 is IA) /* Если переменная типа CB является переменной типа класса, реализующего запрашиваемый интерфейс IA, то оператор is вернет значение true. */ {Console.WriteLine ("varb1 - это ссылка на класс, который реализует интерфейс IA");} // Создание объекта типа интерфейса IA IA ivar=(IA)varb1; if (ivar is IA) {Console.WriteLine ("ivar - это ссылка на интерфейс IA");} bool var1=ivar.F1(); Console.WriteLine("Вызов метода F1 интерфейса IA: {0}",var1); // Приведение объекта к типу интерфейса Object ivar1 = varb1 as IA; if (ivar1 != null) Console.WriteLine ( "ivar1 - это ссылка на интерфейс IA"); } } } using System; namespace MyAClass1 { public class CB : MyAClass1.CA,IA {public CB() { } public bool F1() { return true; } public int F2(int a) { return a*10; } } interface IA { bool F1();} } using System; namespace MyAClass1 { public abstract class CA { public CA() { } public abstract int F2(int a); } }
    Листинг 16.2.

    Производные классы

    В среде VisualStudio.NET новый производный класс можно создать, используя окно ClassView (выполнив в нем команду контекстного меню Add|Add Class). Рисунок 16.1 иллюстрирует страницы диалога C# Class Wizard, предлагаемого средой VisualStudio.NET для создания нового класса.
    Производные классы
    Рис. 16.1.  Диалог C# Class Wizard
    Имя создаваемого класса указывается в поле Class Name на странице Class Options диалога C# Class Wizard.
    В поле Namespace указывается пространство имен, к которому будет принадлежать создаваемый класс. По умолчанию проект размещается в пространстве имен, одноименным с именем проекта.
    В поле Access выбирается модификатор доступа для создаваемого класса.
    Для класса в языке C# возможно использование двух модификаторов доступа:
  • public - определяет, что нет ограничений на использование класса;
  • internal - определяет, что класс будет доступен для файлов, входящих в ту же сборку.

  • Сборка - это физический файл, который состоит из нескольких PE-файлов (portable executable), генерируемых компилятором среды .NET. В сборку входит декларация (manifest), содержащая описание сборки для управляющей среды .NET.
    Класс может имеет один из следующих модификаторов класса:
  • abstract - определяет, что класс должен быть использован только как базовый класс других классов. Такие классы называются абстрактными классами;
  • sealed - определяет, что класс нельзя использовать в качестве базового класса. Такие классы в языке C# иногда называются изолированными классами.

  • Очевидно, что изолированный класс не может быть одновременно и абстрактным классом.
    Объявление класса может иметь следующее формальное описание:
    МодификаторДоступа МодификаторКласса class ИмяКласса : ИмяНаследуемогоКласса {ТелоКласса }
    Тело класса содержит описание переменных, методов и вложенных классов и заключается в фигурные скобки. В частном случае тело класса может не содержать ни одного объявления.
    Например:
    namespace CA1 { public abstract class Class2 : CA1.Class1 { public Class2() { // TODO: Add constructor logic here } } }

    Виртуальные методы

    Виртуальные методы объявляются в базовом классе с ключевым словом virtual, а в производном классе могут быть переопределены. Метод, который переопределяет виртуальный, указывается ключевым словом override. Прототипы виртуальных методов как в базовом, так и в производном классе должны быть одинаковы.
    Применение виртуальных методов позволяет реализовывать механизм позднего связывания.
    На этапе компиляции строится только таблица виртуальных методов, а конкретный адрес проставляется уже на этапе выполнения.
    При вызове метода - члена класса действуют следующие правила:
  • для виртуального метода вызывается метод, соответствующий типу объекта, на который имеется ссылка;
  • для невиртуального метода вызывается метод, соответствующий типу самой ссылки.

  • При позднем связывании определение вызываемого метода происходит на этапе выполнения (а не при компиляции) в зависимости от типа объекта, для которого вызывается виртуальный метод.
    При раннем связывании определение вызываемого метода происходит на этапе компиляции.
    Например:
    using System; namespace MyDerriv1 { class Class1 { static void Main(string[] args) { // Тип объекта и тип ссылки совпадают CA var1; var1=new CA(); // Вызывается метод класса CA Console.WriteLine (var1.F1()); // Вызывается метод класса CA Console.WriteLine (var1.F2()); // Тип объекта - CB , а тип ссылки - CA CA var2; var2=new CB(); // Вызывается метод класса CA Console.WriteLine (var2.F1()); // Вызывается метод класса CB Console.WriteLine (var2.F2()); } } } // Класс CA using System; namespace MyDerriv1 { public class CA { public CA() { } public int F1() { return 1; } public virtual string F2() {return "Метод F2 класса CA";} } } // Класс CB using System; namespace MyDerriv1 { public class CB : MyDerriv1.CA { public CB() { } public int F1() {return 2; } // Переопределение виртуального метода F2 public override string F2() { return "Метод F2 класса CB"; } } }
    Листинг 16.1.

    Вложенные классы

    Язык C# позволяет создавать вложенные классы. Вложенный класс объявляется как член другого класса.
    Права доступа для вложенного класса могут быть или меньшими, или такими же, как у содержащего его класса. Так, вложенный класс не может быть общедоступным, если содержащий его класс объявлен как internal.
    При доступе к имени вложенного класса из членов внешнего класса квалификация именем внешнего класса не требуется.
    Например:
    using System; namespace MyNClass1 {class Class1 { static void Main(string[] args) {Class1.Class2 var1= new Class1.Class2(); // Эквивалентно // записи: Class2 var1= new Class2(); //Вызов метода вложенного класса Console.WriteLine( var1.F1()); } class Class2 { private int a=12345; public int F1() {return this.a;} } } }
    Вложенные классы

    Введение в программирование

    Атрибуты

    Язык С# позволяет создавать атрибуты для различных элементов языка, таких как типы, методы, поля и свойства классов. Данные, хранимые в атрибутах, можно запрашивать во время выполнения приложения. Атрибуты - это механизм, позволяющий создавать самоописывающиеся приложения.
    Использование атрибутов позволяет получать метаданные периода выполнения.Каждый атрибут - это экземпляр класса, производного от System.Attribute.
    Назначаемый типу или члену класса атрибут указывается в квадратных скобках перед типом или членом класса.
    Про атрибут, указанный для класса, иногда говорят, что этот атрибут "прикреплен к целевому типу".
    Класс Attribute пространства имен System предоставляет следующие члены класса:
  • GetType - получает объект типа Type текущего экземпляра;
  • ToString - возвращает строку, описывающую данный объект;
  • IsDefined - определяет, существует ли атрибуты заданного типа, назначенные указываемому члену класса;
  • GetCustomAttribute - запрашивает атрибут заданного типа для указанного члена класса.

  • Для класса Attribute определено свойство TypeId, определяющее уникальный идентификатор атрибута.

    Доступ к атрибуту

    Значения атрибутов или их существование могут быть запрошены во время выполнения приложения.
    При запросе для класса или для члена класса данных о прикрепленных к нему атрибутах применяется отражение. Отражением называется функция, используемая во время выполнения приложения для получения метаданных, в том числе и заданных атрибутами.
    Для реализации отражения библиотека NET Framework предоставляет несколько классов, базовым для которых служит класс отражения System.Reflection.
    Основные методы отражения, используемые для запроса атрибутов, предоставляются классами System.Reflection.MemberInfo и System.Reflection.Assembly. Так, метод GetCustomAttributes позволяет определить атрибуты, присущие данному объекту.
    Например:
    class MyClass { public static void Main() { System.Reflection.MemberInfo info = typeof(MyClass); object[] attr = info.GetCustomAttributes(true); for (int i = 0; i < attr.Length; i ++) { System.Console.WriteLine(attr[i]); } } }
    В результате выполнения данного кода в массив будут помещены классы всех назначенных атрибутов, а также класс System.Reflection.DefaultMemberAttribute. Доступ к типу объекта может быть реализован посредством класса Type . Метод Object.GetType возвращает объект типа Type , представляющий тип экземпляра объекта. Объект типа Type представляет собой ассоциированный с типом объект, используемый для доступа к метаданным типа.
    Используя класс Type, можно создать объект для типа, экземпляр которого еще не был создан.
    Например:
    Type t= typeof(MyClass1);
    Для создания объекта типа, ассоциированного с типом существующего экземпляра объекта, следует использовать метод GetType.
    Например:
    Type t = obj1.GetType(); , где obj1 экземпляр класса MyClass1.
    При использовании объекта типа атрибута метод GetCustomAttribute возвращает значения атрибута, который назначен указанному параметрами объекту: первый параметр метода определяет ассоциированный объект, а второй - указывает класс атрибута.
    Например:
    MyAttribute MyAttr = (MyAttribute) Attribute.GetCustomAttribute( t, typeof(MyAttribute));

    Следующий пример иллюстрирует доступ к значениям атрибутов.

    class Class1 { static void Main(string[] args) { // Создание объекта, ассоциированного с типом AClass1 Type t= typeof(AClass1); MyAttribute MyAttr = (MyAttribute) Attribute.GetCustomAttribute( t, typeof (MyAttribute)); if(null == MyAttr) {Console.WriteLine("Атрибут не найден");} else { Console.WriteLine("Атрибут name = {0}, атрибут kod = {1}" , MyAttr.Name, // Возвращает значение // поля Name атрибута MyAttribute MyAttr.Kod); } } } [AttributeUsage(AttributeTargets.All)] public class MyAttribute : System.Attribute { private string name; private int kod; public MyAttribute(string name) {this.name = name; this.kod = 10; } public string Name { get { return name;} } public int Kod { get { return kod; } set {kod=value; } } }

    [My("NameOfClass", Kod=123)] public class AClass1 { public AClass1() { } private int [] iArr = new int[10]; public int this[int ind1] { get { return iArr[ind1];} set { iArr[ind1]= value; } } }

    Листинг 17.1.

    с типом AClass1 Type t=

    class Class1 { static void Main(string[] args) { // Создание объекта, ассоциированного с типом AClass1 Type t= typeof(AClass1); MyAttribute MyAttr = (MyAttribute) Attribute.GetCustomAttribute( t, typeof (MyAttribute)); if(null == MyAttr) {Console.WriteLine("Атрибут не найден");} else { Console.WriteLine("Атрибут name = {0}, атрибут kod = {1}" , MyAttr.Name, // Возвращает значение // поля Name атрибута MyAttribute MyAttr.Kod); } } } [AttributeUsage(AttributeTargets.All)] public class MyAttribute : System.Attribute { private string name; private int kod; public MyAttribute(string name) {this.name = name; this.kod = 10; } public string Name { get { return name;} } public int Kod { get { return kod; } set {kod=value; } } }

    [My("NameOfClass", Kod=123)] public class AClass1 { public AClass1() { } private int [] iArr = new int[10]; public int this[int ind1] { get { return iArr[ind1];} set { iArr[ind1]= value; } } }

    Листинг 17.1.
    Закрыть окно





    class Class1

    { static void Main(string[] args)

    {

    // Создание объекта, ассоциированного с типом AClass1

    Type t= typeof(AClass1);

    MyAttribute MyAttr =

    (MyAttribute) Attribute.GetCustomAttribute(

    t,

    typeof (MyAttribute));

    if(null == MyAttr)

    {Console.WriteLine("Атрибут не найден");}

    else

    {

    Console.WriteLine("Атрибут name = {0},

    атрибут kod = {1}" ,

    MyAttr.Name, // Возвращает значение

    // поля Name атрибута MyAttribute

    MyAttr.Kod); }

    }

    }

    [AttributeUsage(AttributeTargets.All)]

    public class MyAttribute : System.Attribute

    { private string name;

    private int kod;

    public MyAttribute(string name)

    {this.name = name; this.kod = 10; }

    public string Name { get { return name;} }

    public int Kod { get { return kod; }

    set {kod=value; } }

    }

    [My("NameOfClass", Kod=123)]

    public class AClass1

    { public AClass1() { }

    private int [] iArr = new int[10];

    public int this[int ind1] {

    get { return iArr[ind1];}

    set { iArr[ind1]= value; } }

    }

    n Число методов public

    public static void Main() { Type myType =(typeof(MyClass1)); // Получить методы с доступом public MethodInfo[] myArrMethodInfo = myType.GetMethods(BindingFlags.Public |BindingFlags.Instance |BindingFlags.DeclaredOnly); Console.WriteLine("\ n Число методов public =:" +myArrMethodInfo.Length); Console.WriteLine("Имена методов public : "); // Отобразить имена всех методов MyPrintMethodInfo(myArrMethodInfo); // Получить методы с защищенным доступом MethodInfo[] myArrMethodInfo1 = myType.GetMethods(BindingFlags.NonPublic |BindingFlags.Instance |BindingFlags.DeclaredOnly); Console.WriteLine("\n Число защищенных методов:" +myArrMethodInfo1.Length); } public static void MyPrintMethodInfo(MethodInfo[] a) { for(int i=0;i
    Листинг 17.2.
    Закрыть окно





    public static void Main()

    {

    Type myType =(typeof(MyClass1));

    // Получить методы с доступом public

    MethodInfo[] myArrMethodInfo =

    myType.GetMethods(BindingFlags.Public

    |BindingFlags.Instance

    |BindingFlags.DeclaredOnly);

    Console.WriteLine("\ n Число методов public =:"

    +myArrMethodInfo.Length);

    Console.WriteLine("Имена методов public : ");

    // Отобразить имена всех методов

    MyPrintMethodInfo(myArrMethodInfo);

    // Получить методы с защищенным доступом

    MethodInfo[] myArrMethodInfo1 =

    myType.GetMethods(BindingFlags.NonPublic

    |BindingFlags.Instance

    |BindingFlags.DeclaredOnly);

    Console.WriteLine("\n Число защищенных методов:"

    +myArrMethodInfo1.Length);

    }

    public static void MyPrintMethodInfo(MethodInfo[] a)

    {

    for(int i=0;i

    {

    MethodInfo myMethodInfo = (MethodInfo)a[i];

    Console.WriteLine("\n" + myMethodInfo.Name);

    }

    }

    Индексаторы на базе многомерных массивов

    Для одного класса может быть создано несколько индексаторов. Индексаторы должны различаться числом параметров.
    Например:
    public class AClass1 { public AClass1() { } private int [] imyArray = new int[20]; public int this[int ind1] { get { return imyArray[ind1]; } set { imyArray[ind1]= value; } } private int [,] imyArray2 = new int[2,10]; public int this[int ind1, int ind2] { get {return imyArray2[ind1,ind2]; } set {imyArray2[ind1,ind2]= value; } } }

    Используемость атрибута

    Атрибуты могут быть использованы для различных элементов языка. Для того чтобы специфицировать, каким образом и для каких элементов можно использовать данный класс атрибута, библиотека NET Framework предоставляет класс System.AttributeUsageAttribute.
    Спецификация используемости атрибута указывается в квадратных скобках перед именем определением класса.
    Например:
    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
    Элементы языка, которым может быть назначен атрибут, указываются значением или набором значений перечислимого типа AttributeTargets.
    Например, для использования данного атрибута только для классов или методов перед определением класса атрибута следует записать:
    [AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)]
    Спецификация используемости атрибута имеет следующее формальное описание:
    [AttributeUsage( доступные_элементы, AllowMultiple=true_или_false, Inherited=наследуемость )]
    Доступные элементы определяют те элементы языка, для которых может быть назначен данный атрибут. По умолчанию используется значение AttributeTargets.All (доступен для всех элементов).
    Если именованный параметр AllowMultiple равен true, то классу или члену класса может быть назначено несколько атрибутов.
    Параметр Inheritedопределяет, наследуется ли данный атрибут производным классом (по умолчанию - false).
    Перечислимый тип AttributeTargets определяет следующее множество значений:
  • All - все элементы языка;
  • Assembly - сборки;
  • Class - классы;
  • Constructor - конструкторы;
  • Field - поля;
  • Method - методы;
  • Property - свойства;
  • Delegate - делегаты;
  • Enum - нумераторы;
  • Event - события;
  • Interface - интерфейсы;
  • Module - модули;
  • Parameter - параметры;
  • ReturnValue - возвращаемые значения;
  • Struct - структуры.


  • Элементы индексатора

    Объект класса, используемого как аксессор, создается обычным образом. Инициализация элементов аксессора указывается как присвоение значений элементам массива. Доступ к элементам аксессора записывается как доступ к элементам массива.
    Например:
    AClass1 ac1= new AClass1(); ac1[0]=5; ac1[1]=6; Console.WriteLine("ac1[0]= {0}, ac1[1]= {1}", ac1[0],ac1[1]);

    Класс Type

    Класс System.Type имеет следующее формальное описание:
    public abstract class Type : MemberInfo, IReflect.
    Две ссылки типа Type на объект будут ссылаться на один и тот же объект только в том случае, если они представляют одинаковый тип.
    Экземпляр типа Type может быть представлен любым из следующих типов:
  • классы;
  • размерные типы (Value types);
  • массивы;
  • интерфейсы;
  • указатели;
  • нумераторы.

  • Ссылка на объект Type, ассоциируемый с типом, может быть получена одним из следующих способов:
  • метод Object.GetType возвращает объект Type, представляющий тип экземпляра объекта;
  • статический метод GetType возвращает объект Type, который представляет тип, указанный посредством своего полного имени;
  • методы Module.GetTypes, Module.GetType, и Module.FindTypes возвращают объект Type, который представляет типы, определенные в модуле. Метод GetTypes позволяет получить массив объектов для всех общедоступных и защищенных типов, определенных в модуле;
  • метод FindInterfaces возвращает отфильтрованный список интерфейсов типов, которые поддерживаются данным типом;
  • метод GetElementType возвращает объект Type, который представляет элемент;
  • методы GetInterfaces и GetInterface возвращают объект Type, который представляет интерфейс, поддерживаемый типом;
  • метод GetTypeArray возвращает массив объектов Type, которые представляют типы, заданные посредством набора объектов;
  • методы GetTypeFromProgIDи GetTypeFromCLSID возвращают объект Type , который указывается через ProgID или CLSID (методы предоставляются для совместимости с СОМ);
  • метод GetTypeFromHandle возвращает объект Type , который указывается посредством дескриптора (метод предоставляется для совместимости);
  • оператор typeof получает объект Type для указанного типа.

  • Метаданные - это информация о выполнимом модуле, получаемая во время выполнения приложения. К такой информации относятся и данные о типе. В случае неправильного указания имени типа возникает исключение. Поэтому указание типа следует заключать в блок try-catch .
    Например:
    try { Type tp=Type.GetType(s); Console.WriteLine("Имя типа : {0}",tp.FullName); } catch (System.NullReferenceException) {Console.WriteLine("Ошибка задания типа");}

    Класс Type предоставляет большой набор свойств для запроса информации по типу, включая следующие:

  • FullName - возвращает имя типа;
  • IsClass - определяет, является ли тип классом;
  • IsAbstract - определяет, является ли тип абстрактным классом;
  • IsNestedPublic - определяет, является ли тип вложенным и общедоступным;
  • IsPublic - определяет, является ли данный тип общедоступным;
  • IsNotPublic - определяет, является ли данный тип защищенным;
  • IsSealed - определяет, является ли тип конечным (не может быть базовым классом);
  • IsArray - определяет, представляет ли указанный тип массив;
  • GUID - возвращает значение типа GUID, ассоциированное с данным типом (такое значение хранится в реестре Windows).

    Например:

    Type myType = typeof(MyClass1); Guid myGuid =(Guid) myType.GUID;

  • IsNestedAssembly - определяет, является ли тип вложенным и видимым только в своей собственной сборке;
  • Module - возвращает модуль (DLL) в котором объявлен данный тип;
  • Namespace - возвращает пространство имен, содержащее данный тип;


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

    Например:

    Type tp=Type.GetType(s); Console.WriteLine("\tПередается по ссылке ? : {0}",tp.IsByRef);

    Методы-аксессоры

    После определения параметра в фигурных скобках указаны два метода-аксессора. get-аксессор возвращает значение данных по указанному индексу,а set-аксессор устанавливает значение данных с указанным индексом. Устанавливаемое значение задается ключевым словом value.
    Индексатор устанавливает и возвращает значения некоторого массива. Такой массив для аксессора должен быть создан. Типы используемого массива и аксессора должны совпадать. Например для целочисленного аксессора можно объявить следующий массив:
    private int [] imyArray = new int[50];
    Теперь, чтобы использовать акссессор, следует:
  • определить возвращаемое методом-аксессором значение (например: return imyArray[ind1];);
  • определить устанавливаемое методом-аксессором значение (например: imyArray[ind1]= value;).

  • В результате класс, содержащий аксессор, будет иметь следующее объявление:
    public class AClass1 { public AClass1() { } private int [] imyArray = new int[20];
    public int this[int ind1] { get { return imyArray[ind1]; } set { imyArray[ind1]= value; } } }

    Назначение атрибута

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

  • Атрибут указывается в квадратных скобках перед элементом, которому он назначается. Назначаемый атрибут инициализируется вызовом конструктора с соответствующими параметрами.
    Класс System.ObsoleteAttribute позволяет помечать код и задавать информацию, которая будет отображаться как Warning во время компиляции приложения. Этот класс предназначается для возможности указания некоторого кода модуля как "устаревшего".Для того чтобы использовать существующий класс для назначаемого методу атрибута, следует:
  • создать метод, использующий атрибут (например, метод, при каждом вызове которого компилятор будет формировать сообщение Warning с указанным в атрибуте кодом);
  • ввести перед определением метода в квадратных скобках имя класса атрибута (например, класса ObsoleteAttribute).

  • Например:
    [ObsoleteAttribute ("Сообщение, отображаемое компилятором как Warning")] public static void M1( ) {return ; // Компилятор будет выдавать предупреждение при // каждом вызове данного метода, которому назначен // соответствующий атрибут. Например: // c:\c#_project\pr1\class1.cs(23,4): warning // CS0618: 'pr1.Class1.M1()' is obsolete: // 'Сообщение, отображаемое компилятором как // Warning' }
    Язык С# при назначении атрибута позволяет не указывать суффикс Attribute. Так, вместо [ObsoleteAttribute("")] можно записать [Obsolete("")].
    Класс атрибута должен иметь хотя бы один public-конструктор.

    Параметры атрибута

    По умолчанию код класса атрибута содержит конструктор без параметров.Для того чтобы иметь возможность при назначении атрибута сохранять для типа или члена класса некоторые параметры, эти параметры надо задать как параметры конструктора класса атрибута. Параметры атрибута могут объявляться как переменные члены класса.
    Для доступа к защищенным переменным членам класса в языке C# используются свойства.
    Для создания свойства в среде проектирования VisualStudio.NET можно использовать мастер построения свойства: для этого в окне Class View следует выделить секцию c именем класса и выполнить команду контекстного меню Add|Add Property.
    В диалоге C# Property Wizard (рис. 17.2) в поле Property Name следует указать имя создаваемого свойства.
    Параметры атрибута
    Рис. 17.2.  Диалог C# Property Wizard
    Тип создаваемого свойства выбирается из списка Property type.
    На панели Accessors переключатели get и set определяют, какие методы-аксессоры будут созданы. Например:
    using System; namespace MyPr1 { [AttributeUsage(AttributeTargets.All)] public class MyAttribute : System.Attribute { private string name; // Используются как private int kod; // параметры атрибута public MyAttribute(string name) { // Конструктор this.name = name; this.kod = 12345; } // Свойство Name public string Name { get { return name; } } // Свойство Kod public int Kod { get { return kod; } set {kod=value; } // Назначение // защищенной переменной члену // класса значения параметра } } } // Для назначения некоторому классу данного // атрибута перед объявлением класса следует // указать строку типа [My("NameClass", Kod=123)]

    Получение информации о методах

    Используя метод GetMetods, можно получить информацию о методах. Такая информация заносится в массив типа MetodInfo.
    Например:
    public static void Main() { Type myType =(typeof(MyClass1)); // Получить методы с доступом public MethodInfo[] myArrMethodInfo = myType.GetMethods(BindingFlags.Public |BindingFlags.Instance |BindingFlags.DeclaredOnly); Console.WriteLine("\n Число методов public =:" +myArrMethodInfo.Length); Console.WriteLine("Имена методов public : "); // Отобразить имена всех методов MyPrintMethodInfo(myArrMethodInfo); // Получить методы с защищенным доступом MethodInfo[] myArrMethodInfo1 = myType.GetMethods(BindingFlags.NonPublic |BindingFlags.Instance |BindingFlags.DeclaredOnly); Console.WriteLine("\n Число защищенных методов:" +myArrMethodInfo1.Length); } public static void MyPrintMethodInfo(MethodInfo[] a) { for(int i=0;i Листинг 17.2.
    Получение информации о методах

    Позиционные и именованные параметры атрибута

    При назначении классу или члену класса атрибута используется конструктор атрибута со списком параметров. Параметры могут быть:
  • позиционными;
  • именованными.

  • Позиционные параметры указываются в порядке, который определяется списком параметров конструктора атрибута. Позиционные параметры всегда должны быть указаны при назначении атрибута.
    Именованные параметры отсутствуют в списке параметров конструктора атрибута. Значения, задаваемые для именованных параметров, используются для инициализации полей и свойств создаваемого экземпляра атрибута. Список именованных параметров указывается через запятую после списка позиционных параметров. Каждый именованный параметр определяется как Имя_параметра=Значение_параметра.
    В предыдущем примере параметр name использовался как позиционный параметр, а kod - как именованный (по умолчанию значение переменной kod, доступной через свойство Kod, устанавливается равным конкретному значению. Если при назначении атрибута явно не будет задан именованный параметр, то при создании экземпляра атрибута будет использовано значение по умолчанию).
    Параметры атрибута могут указываться константными значениями следующих типов:
  • bool, byte, char, short, int, long, float, double;
  • string;
  • System.Type;
  • enums;
  • object (аргумент для параметра атрибута типа object должен быть константным значением вышеуказанных типов);
  • одноразмерные массивы любых вышеуказанных типов.


  • Создание атрибута

    Создание атрибута начинается с создания класса, реализующего атрибут. Такой класс должен быть наследуем от любого класса атрибута. Класс атрибута всегда должен иметь модификатор доступа public.
    Класс атрибута всегда непосредственно или опосредованно наследуется от класса System.Attribute.
    Например:
    public class MyAttribute : System.Attribute { public MyAttribute() { } }

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

    Индексатор позволяет работать с классом или структурой таким образом, как если бы это были массивы. Индексация класса выполняется по индексу, указываемому как параметр. Иногда классы, используемые как индексаторы, называют классами-индексаторами.
    Объявление индексатора может иметь следующее формальное описание:
    атрибуты] [модификаторы] тип this [[атрибуты] тип_параметра идентификатор_параметра .,...] {объявление аксессоров}
    Индексатор должен иметь как минимум один параметр. Тип и идентификатор параметра указываются в квадратных скобках после ключевого слова this.
    Среда проектирования Visual Studio.NET позволяет использовать мастер создания индексатора: для этого в окне Class View следует выделить имя класса и выполнить команду контекстного меню Add|Add Indexer.
    Диалог C# Indexer Wizard (рис. 17.1) позволяет определить параметры создаваемого индексатора.
    Создание индексаторов
    Рис. 17.1.  Диалог C# Indexer Wizard
    В поле Indexer Аcess указывается модификатор доступа для индексатора. Это могут быть следующие модификаторы:
  • public - доступ не ограничен;
  • protected - доступ ограничен только наследуемыми классами;
  • internal - доступ ограничен рамками текущего проекта;
  • private - доступ ограничен рамками данного класса;
  • protected internal - ограничение доступа наследуемыми классами текущего проекта.

  • В поле Indexer Type определяется тип массива, используемого для индексатора. В качестве типа индексатора может быть выбран любой из следующих типов:
  • bool - логическое значение true или false;
  • decimal - 128-битовый тип данных (1,0 * 10-28 до 7,9 * 1028);
  • int - 32-битовое целочисленное значение;
  • sbyte - знаковое 8-битовое целое (от - 128 до 127);
  • uint - беззнаковое 32-битовое целочисленное значение (от 0 до 4 294 967 295);
  • byte;
  • double - 64-битовый тип данных (±5,0 * 10-324 до ±1,7 * 10308);
  • long - 64-битовое целочисленное значение;
  • string;
  • ulong;
  • char;
  • float- 32-битовый тип данных (±1.5 * 10-45 до ±3.4 * 1038);
  • object;
  • short;
  • ushort.

  • Поле Parameter Name содержит имя параметра.
    На панели Indexer Modifiers можно выбрать одну из следующих опций:
  • None - индексатор не содержит дополнительных модификаторов;
  • Virtual - реализация индексатора может быть переопределена в наследуемых классах, для индексатора указывается ключевое слово virtual;
  • Abstract - индексатор является членом абстрактного класса, для индексатора указывается ключевое слово abstract.

  • Ключевое слово this используется как имя индексатора, так как с классом, содержащим индексатор, можно манипулировать как с массивом.
    Например:
    public int this[int ind1] // Индексатор типа int // с одним параметром типа int - ind1 { get { return 0; } set { } }

    Введение в программирование

    DLL-библиотеки

    Для того чтобы вызвать метод из DLL-библиотеки, его следует объявить с модификатором extern и атрибутом DllImport.
    Например:
    [DllImport("Имя_библиотеки.dll")] static extern int M1(int i1, string s1);
    Класс атрибута DllImportAttribute имеет следующее определение:
    namespace System.Runtime.InteropServices { [AttributeUsage(AttributeTargets.Method)] public class DllImportAttribute: System.Attribute { public DllImportAttribute(string dllName) {...} public CallingConvention CallingConvention; public CharSet CharSet; // Набор символов public string EntryPoint; // Имя метода public bool ExactSpelling; // Точное // соответствие написания имени метода public bool PreserveSig; // Определяет, будет ли // предотвращено изменение сигнатуры метода (по умолчанию // установлено значение true). // При изменении сигнатуры возвращаемое значение будет // иметь тип HRESULT и будет добавлен out-параметр retval public bool SetLastError; public string Value { get {...} } } }
    Атрибут DllImport имеет один позиционный параметр, определяющий имя DLL-библиотеки, и пять именованных параметров. Параметр EntryPoint позволяет указать имя метода из DLL-библиотеки. При этом имя метода, помечаемого данным атрибутом, может отличаться от имени метода в DLL-библиотеке.
    Например:
    [DllImport("myDll.dll", EntryPoint="M1")] static extern int New_name_of_M1(int i1, string s1);
    Именованный параметр CharSet определяет используемый в DLL-библиотеке набор символов (ANSI или Unicode). По умолчанию используется значение CharSet.Auto.
    Например:
    [DllImport("myDll.dll", CharSet CharSet.Ansi)] static extern int M1(int i1, string s1);
    Для каждого типа параметра при вызове метода из DLL-библиотеки выполняющая среда .NET производит подразумеваемое по умолчанию преобразование типов (например, тип string в тип LPSTR (Win32). Для того чтобы явным образом указать тип, используемый в методе DLL-библиотеки, следует применить к параметру атрибут MarshalAsAttribute.
    Например:
    [DllImport("myDll.dll", CharSet CharSet.Unicode)] static extern int M1(int i1, [MarshalAs(UnmanagedType.LPWStr)] string s1);
    Атрибут MarshalAsAttribute может быть прикреплен к полю, методу или параметру. Прикрепление данного атрибута к методу позволяет указать явное преобразование типа для возвращаемого значения. DLL-библиотеки

    Параметр callback используется для вызова

    using System; namespace MyDelegatе1 { class Class1 {[STAThread] static void Main(string[] args) { CA var1= new CA(); // Создание экземпляра делегата CA.Metod1Callback myCall = new CA.Metod1Callback(Class1.Metod2); // Значение // параметра, передаваемое методу обратного // вызова Class1.Metod2, определено // в методе Metod1 как "1".

    // Выполнение метода обратного вызова (Metod2), // переданного в качестве параметра CA.Metod1(myCall); } static void Metod2 (string str2){ Console.WriteLine("Выполняется метод Metod2"); Console.WriteLine(str2); } } } using System; namespace MyDelegatе1 { public class CA { public CA() { } public delegate void Metod1Callback(string str1); public static void Metod1(Metod1Callback callback) { Console.WriteLine("Выполняется метод Metod1"); // Параметр callback используется для вызова // метода обратного вызова и передачи ему // параметра (строки "1") callback("1"); } } }

    Листинг 18.1.
    Закрыть окно





    using System;

    namespace MyDelegatе1

    {

    class Class1

    {[STAThread]

    static void Main(string[] args) {

    CA var1= new CA();

    // Создание экземпляра делегата

    CA.Metod1Callback myCall =

    new CA.Metod1Callback(Class1.Metod2); // Значение

    // параметра, передаваемое методу обратного

    // вызова Class1.Metod2, определено

    // в методе Metod1 как "1".

    // Выполнение метода обратного вызова (Metod2),

    // переданного в качестве параметра

    CA.Metod1(myCall);

    }

    static void Metod2 (string str2){

    Console.WriteLine("Выполняется метод Metod2");

    Console.WriteLine(str2);

    }

    }

    }

    using System;

    namespace MyDelegatе1

    {

    public class CA

    { public CA() { }

    public delegate void Metod1Callback(string str1);

    public static void Metod1(Metod1Callback callback)

    {

    Console.WriteLine("Выполняется метод Metod1");

    // Параметр callback используется для вызова

    // метода обратного вызова и передачи ему

    // параметра (строки "1")

    callback("1");

    }

    }

    }

    Использование делегата для вызова методов

    Делегат объявляет новый ссылочный тип.
    Делегат позволяет передавать функцию как параметр.
    Объявление делегата имеет следующее формальное описание:
    [атрибуты] [модификаторы] delegate тип_результата имя_делегата ([список_формальных параметров]);
    Модификаторами делегата могут быть:
  • new
  • public
  • protected
  • private
  • internal
  • unsafe (если в списке параметров используется указатель).

  • Тип результата должен соответствовать типу результата используемого метода. При создании делегата требуется, чтобы передаваемый как делегат метод имел ту же сигнатуру метода, что и в объявлении делегата.
    Например:
    using System; delegate void MyDelegate(); // Этот делегат позволяет // вызывать методы без параметров // и без возвращаемого значения
    Для вызова метода через делегата следует создать экземпляр делегата, передав ему в качестве параметра метод, имеющий ту же сигнатуру, что и у делегата, а затем выполнить вызов. Для статического метода в качестве параметра передается имя метода, квалифицированное именем класса.
    Например:
    using System; delegate void MyDelegate(); namespace MyDelegat1 { class Class1 {[STAThread] static void Main(string[] args) { CA var1= new CA(); // Экземпляр делегата для нестатического метода: MyDelegate F_d = new MyDelegate(var1.F_Instance); F_d(); // Экземпляр делегата для статического метода: F_d = new MyDelegate(CA.F_Static); F_d(); } } public class CA { public CA() { } public void F_Instance() { Console.WriteLine("Вызов метода класса с использованием делегата"); } public static void F_Static() { Console.WriteLine("Вызов статического метода с использованием делегата"); } }

    Небезопасный код

    Фрагмент небезопасного кода следует помечать ключевым словом unsafe.
    Например:
    int i1; unsafe {int *i2=&i1;}
    Ключевым словом unsafe требуется обязательно помечать любой фрагмент кода, который содержит указатель.
    Модификатор unsafe может быть указан для методов, свойств и конструкторов (за исключением статических конструкторов), а также для блоков кода.
    Например:
    using System; class Class1 { unsafe static void M1 (int* p) // Небезопасный код: указатель на int { *p *= *p; } // *p - доступ к значению unsafe public static void Main() // Небезопасный код: применен оператор // получения адреса (&) { int i = 4; M1 (&i); Console.WriteLine (i); } }
    Чтобы использовать небезопасный код, следует установить опцию компилятора /unsafe. Для этого достаточно выбрать имя проекта в окне Solution Explorer и через контекстное меню вызвать диалогProperty Pages (рис. 18.1) , а затем на странице Configuration Properties | Build установить значение опции Allow unsafe code blocks равным True.
    Небезопасный код
    Рис. 18.1.  Диалог Property Pages
    Указатели можно использовать только с размерными типами, массивами и строками. При задании указателя на массив первый элемент массива должен быть размерного типа.
    Выполняющая среда .NET для эффективного управления памятью при удалении одних объектов "перемещает" другие объекты, чтобы исключить фрагментацию памяти свободными блоками памяти. Таким образом, выполняющая среда .NET по умолчанию не гарантирует, что объект, на который получен указатель, всегда будет иметь один и тот же адрес. Для предотвращения перемещения объекта следует использовать оператор fixed, который имеет следующее формальное описание:
    fixed ( тип* имя_указателя = выражение ) выполняемый_оператор_или_блок
    В качестве типа можно указывать любой неуправляемый тип или void. Выражение является указателем на заданный тип. Фиксация объекта применяется только для указанного выполняемого оператора или блока. Доступ к фиксированной переменной не ограничен областью видимости небезопасного кода.
    Поэтому фиксированная переменная может указывать на значение, располагаемое в более широкой области видимости, чем данная область видимости небезопасного кода. При этом компилятор C# не выдает предупреждений о такой ситуации.

    Однако компилятор C# не позволит установить указатель на управляемую переменную вне оператора fixed.

    Например:

    class Point { public int x, y; } class Class1 {[STAThread] static void Main(string[] args) { unsafe { Point pt = new Point(); // pt - это управляемая // переменная fixed ( int* p = &pt.x ) { *p = 1 } // pt.x - // указывает на значение // размерного типа } } }

    Одним оператором fixed можно фиксировать несколько указателей, но только в том случае, если они одного типа.

    Например:

    fixed (byte* pa1 = array1, pa2 = array2) {...}

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

    Например:

    fixed (int* p1 = &p.x) fixed (double* p2 = &array1[5]) { }

    Указатели, которые инициализированы оператором fixed, не могут быть изменены. Если объект, на который устанавливается указатель, размещается в стеке (например, переменная типа int), то его местоположение фиксировать не требуется.

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

    тип * имя_указателя = stackalloc тип [ выражение ];

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

    Например:

    using System; class Class1 {public static unsafe void Main() { int* a1 = stackalloc int[100]; int* p = a1; // Указатель на первый // элемент массива *p++ = *p++ = 1; for (int i=2; i<100; ++i, ++p) *p = p[-1] + p[-2]; for (int i=0; i<10; ++i) Console.WriteLine (a1[i]); } }

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

    Применение делегатов как методов обратного вызова

    Метод обратного вызова используется для передачи одному методу в качестве параметра другого метода, который может быть вызван через переданный "указатель" на метод.
    Методы обратного вызова могут применяться в различных целях. Наиболее часто их используют для реализации асинхронной обработки данных или определения кода, выполняющего дополнительную обработку данных.
    Например:
    using System; namespace MyDelegatе1 { class Class1 {[STAThread] static void Main(string[] args) { CA var1= new CA(); // Создание экземпляра делегата CA.Metod1Callback myCall = new CA.Metod1Callback(Class1.Metod2); // Значение // параметра, передаваемое методу обратного // вызова Class1.Metod2, определено // в методе Metod1 как "1".
    // Выполнение метода обратного вызова (Metod2), // переданного в качестве параметра CA.Metod1(myCall); } static void Metod2 (string str2){ Console.WriteLine("Выполняется метод Metod2"); Console.WriteLine(str2); } } } using System; namespace MyDelegatе1 { public class CA { public CA() { } public delegate void Metod1Callback(string str1); public static void Metod1(Metod1Callback callback) { Console.WriteLine("Выполняется метод Metod1"); // Параметр callback используется для вызова // метода обратного вызова и передачи ему // параметра (строки "1") callback("1"); } } }
    Листинг 18.1.
    В результате выполнения этого приложения сначала будет вызван метод Metod1, а затем Metod2.

    Применение неуправляемого кода

    По умолчанию приложения на C# относятся к управляемому коду. Но при необходимости управляемый код может взаимодействовать с неуправляемым кодом. К неуправляемому коду, вызываемому из управляемых C# приложений, можно отнести функции DLL-библиотек и сервисы COM-компонентов. Приложение управляемого кода на языке C# также может включать фрагменты небезопасного кода. Небезопасный код тоже относится к неуправляемому коду, так как выделение и освобождение памяти в нем не контролируется исполняющей средой .NET.

    Введение в программирование

    Класс диалога имеет следующее объявление

    // Заголовочный файл class CD1App : public CWinApp {public: CD1App(); public: virtual BOOL InitInstance(); // Первый // выполняемый метод // Implementation DECLARE_MESSAGE_MAP() }; extern CD1App theApp; // Переменная - приложение // Файл реализации D1.cpp #include "stdafx.h" #include "D1.h" #include "D1Dlg.h" // CD1App BEGIN_MESSAGE_MAP(CD1App, CWinApp) // Обрабатываемые события ON_COMMAND(ID_HELP, &CWinApp::OnHelp) END_MESSAGE_MAP() CD1App::CD1App(){ } // Конструктор CD1App theApp; BOOL CD1App::InitInstance() { CWinApp::InitInstance(); AfxEnableControlContainer(); SetRegistryKey(_T("Local AppWizard-Generated Applications")); CD1Dlg dlg; // Создание объекта диалога m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal(); // Отображение // диалога if (nResponse == IDOK) { } else if (nResponse == IDCANCEL) { } return FALSE; // Завершение приложения }

    Класс диалога имеет следующее объявление и реализацию:

    // Заголовочный файл class CD1Dlg : public CDialog {public: CD1Dlg(CWnd* pParent = NULL); // Конструктор enum { IDD = IDD_D1_DIALOG }; // Ресурс диалога protected: // Поддержка DDX/DDV: virtual void DoDataExchange(CDataExchange* pDX); // Реализация protected: HICON m_hIcon;

    // Функции таблицы обрабатываемых событий virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() }; // Файл реализации D1Dlg.cpp #include "stdafx.h" #include "D1.h" #include "D1Dlg.h" class CAboutDlg : public CDialog // Класс // вспомогательного диалога {public: CAboutDlg(); enum { IDD = IDD_ABOUTBOX }; // Ресурс диалога protected: virtual void DoDataExchange(CDataExchange* pDX); protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX);} BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP() // Класс окна диалога приложения CD1Dlg::CD1Dlg(CWnd* pParent /*=NULL*/) : CDialog(CD1Dlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CD1Dlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CD1Dlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() END_MESSAGE_MAP() // Методы обработки событий BOOL CD1Dlg::OnInitDialog() { CDialog::OnInitDialog(); ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); // Указатель // на системное меню if (pSysMenu != NULL) // Добавление пунктов к { CString strAboutMenu; //системному меню strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } SetIcon(m_hIcon, TRUE); // Определение крупной // пиктограммы SetIcon(m_hIcon, FALSE); // Определение мелкой пиктограммы return TRUE; } void CD1Dlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } void CD1Dlg::OnPaint() { CDialog::OnPaint(); }

    HCURSOR CD1Dlg::OnQueryDragIcon() // Запрос курсора { return static_cast(m_hIcon); }
    Листинг 19.1.
    Закрыть окно





    END_MESSAGE_MAP()

    // Класс окна диалога приложения

    CD1Dlg::CD1Dlg(CWnd* pParent /*=NULL*/)

    : CDialog(CD1Dlg::IDD, pParent)

    { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); }

    void CD1Dlg::DoDataExchange(CDataExchange* pDX)

    { CDialog::DoDataExchange(pDX); }

    BEGIN_MESSAGE_MAP(CD1Dlg, CDialog)

    ON_WM_SYSCOMMAND()

    ON_WM_PAINT()

    ON_WM_QUERYDRAGICON()

    END_MESSAGE_MAP()

    // Методы обработки событий

    BOOL CD1Dlg::OnInitDialog()

    { CDialog::OnInitDialog();

    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE); // Указатель

    // на системное меню

    if (pSysMenu != NULL) // Добавление пунктов к

    { CString strAboutMenu; //системному меню

    strAboutMenu.LoadString(IDS_ABOUTBOX);

    if (!strAboutMenu.IsEmpty())

    { pSysMenu->AppendMenu(MF_SEPARATOR);

    pSysMenu->AppendMenu(MF_STRING,

    IDM_ABOUTBOX, strAboutMenu);

    }

    }

    SetIcon(m_hIcon, TRUE); // Определение крупной

    // пиктограммы

    SetIcon(m_hIcon, FALSE); // Определение мелкой пиктограммы

    return TRUE;

    }

    void CD1Dlg::OnSysCommand(UINT nID, LPARAM lParam)

    { if ((nID & 0xFFF0) == IDM_ABOUTBOX)

    { CAboutDlg dlgAbout; dlgAbout.DoModal(); }

    else { CDialog::OnSysCommand(nID, lParam); }

    }

    void CD1Dlg::OnPaint() { CDialog::OnPaint(); }

    HCURSOR CD1Dlg::OnQueryDragIcon() // Запрос курсора

    { return static_cast(m_hIcon); }

    данного диалога или NULL HINSTANCE

    typedef struct tagOFN { DWORD lStructSize; // Длина структуры в байтах HWND hwndOwner; // Дескриптор окна владельца // данного диалога или NULL HINSTANCE hInstance; LPCTSTR lpstrFilter; // Указатель на буфер, содержащий // пары null-ограниченных строк: // первая строка - это описание // фильтра (например: "Программы"), // вторая строка - шаблон // (например: "*.exe;*.com")" LPTSTR lpstrCustomFilter; DWORD nMaxCustFilter; DWORD nFilterIndex; LPTSTR lpstrFile; // Указатель на буфер, // который содержит // имя файла, используемое для // инициализации поля File Name, // или NULL. При успешном завершении // функции GetOpenFileName или //GetSaveFileName поле содержит // логический диск, путь и имя // выбранного файла. DWORD nMaxFile; LPTSTR lpstrFileTitle; // Указатель на буфер, // содержащий имя и расширение выбранного файла DWORD nMaxFileTitle; LPCTSTR lpstrInitialDir; // Указатель на null- // ограниченную строку, которая представляет каталог, // используемый для инициализации диалога LPCTSTR lpstrTitle; DWORD Flags; WORD nFileOffset; WORD nFileExtension; LPCTSTR lpstrDefExt; LPARAM lCustData; LPOFNHOOKPROC lpfnHook; LPCTSTR lpTemplateName; #if (_WIN32_WINNT >= 0x0500) void * pvReserved; DWORD dwReserved; DWORD FlagsEx; #endif // (_WIN32_WINNT >= 0x0500) } OPENFILENAME, *LPOPENFILENAME;

    Листинг 19.2.
    Закрыть окно





    typedef struct tagOFN {

    DWORD lStructSize; // Длина структуры в байтах

    HWND hwndOwner; // Дескриптор окна владельца

    // данного диалога или NULL

    HINSTANCE hInstance;

    LPCTSTR lpstrFilter; // Указатель на буфер, содержащий

    // пары null-ограниченных строк:

    // первая строка - это описание

    // фильтра (например: "Программы"),

    // вторая строка - шаблон

    // (например: "*.exe;*.com")"

    LPTSTR lpstrCustomFilter;

    DWORD nMaxCustFilter;

    DWORD nFilterIndex;

    LPTSTR lpstrFile; // Указатель на буфер,

    // который содержит

    // имя файла, используемое для

    // инициализации поля File Name,

    // или NULL. При успешном завершении

    // функции GetOpenFileName или

    //GetSaveFileName поле содержит

    // логический диск, путь и имя

    // выбранного файла.

    DWORD nMaxFile;

    LPTSTR lpstrFileTitle; // Указатель на буфер,

    // содержащий имя и расширение выбранного файла

    DWORD nMaxFileTitle;

    LPCTSTR lpstrInitialDir; // Указатель на null-

    // ограниченную строку, которая представляет каталог,

    // используемый для инициализации диалога

    LPCTSTR lpstrTitle;

    DWORD Flags;

    WORD nFileOffset;

    WORD nFileExtension;

    LPCTSTR lpstrDefExt;

    LPARAM lCustData;

    LPOFNHOOKPROC lpfnHook;

    LPCTSTR lpTemplateName;

    #if (_WIN32_WINNT >= 0x0500)

    void * pvReserved;

    DWORD dwReserved;

    DWORD FlagsEx;

    #endif // (_WIN32_WINNT >= 0x0500)

    } OPENFILENAME, *LPOPENFILENAME;

    Класс CColorDialog

    Класс CColorDialog предназначается для реализации стандартного диалога Color, используемого для выбора цвета. Структура CHOOSECOLOR применяется для инициализации диалога. Для отображения стандартного диалога Color вызывается метод ChooseColor.
    Например:
    CHOOSECOLOR cc; // Структура для инициализации диалога static COLORREF acrCustClr[16]; // Массив цветов HWND hwnd; // Окно владелец HBRUSH hbrush; // Указатель кисти static DWORD rgbCurrent; // Первоначально выбранный цвет ZeroMemory(&cc, sizeof(cc)); cc.lStructSize = sizeof(cc); cc.hwndOwner = hwnd; cc.lpCustColors = (LPDWORD) acrCustClr; cc.rgbResult = rgbCurrent; cc.Flags = CC_FULLOPEN | CC_RGBINIT;
    if (ChooseColor(&cc)==TRUE) { hbrush = CreateSolidBrush(cc.rgbResult); rgbCurrent = cc.rgbResult; }
    Класс CColorDialog

    Класс CDialog

    Класс CDialog является базовым классом, используемым для отображения на экране диалоговых окон, называемых также диалогами.
    Есть два типа диалоговых окон - модальные и немодальные.
    Как уже отмечалось, для реализации диалога следует создать в редакторе диалога шаблон диалогового окна, а затем с помощью ClassWizard (или вручную) создать производный класс от CDialog и определить в нем необходимые методы - обработчики сообщений для расположенных в используемом шаблоне диалога элементов управления.
    ClassWizard автоматически будет добавлять список обрабатываемых сообщений в таблицу сообщений производного класса, а в заголовочном файле будет указан макрос DECLARE_MESSAGE_MAP (), который указывает, что класс содержит таблицу сообщений.
    Класс CDialog

    Для создания диалоговых окон на основе существующего ресурса диалога можно использовать:
  • метод DoModal (для модального диалога);
  • метод Create (для немодального диалога);

  • Если шаблон диалога отсутствует, то можно создать шаблон диалога, используя структуру DLGTEMPLATE, а затем, после создания объекта диалога, вызвать методы CreateIndirect или InitModalIndirect и DoModal.
    Модальное диалоговое окно автоматически закрывается при щелчке пользователя на кнопках типа OK или Cancel или при вызове метода EndDialog. Отметим, что метод EndDialog только скрывает окно диалога, а для его удаления следует использовать функцию DestroyWindow.
    Для обмена значениями с элементом управления используется метод CWnd::UpdateData. Этот метод автоматически вызывается и при щелчке пользователя на кнопке типа OK, и при инициализации элементов управления методом OnInitDialog.
    Метод OnInitDialog вызывается после создания всех элементов управления диалогового окна, но перед их отображением.
    Для определения фона диалоговых окон используется метод CWinApp::SetDialogBkColor.
    Последовательность создания диалогового окна включает следующие шаги:
  • проектирование в редакторе диалога шаблона диалогового окна с включением в него всех требуемых элементов управления и настройки их свойств;
  • создание класса, производного от CDialog, с описанием в нем переменных и обработчиков событий, а также указанием используемого шаблона диалога;
  • определение для каждого элемента управления переменной или объекта, используемых для доступа к значению данного элемента управления;
  • определение необходимых методов обработчиков событий для каждого элемента управления;
  • создание объекта разработанного производного класса диалога (фактически вызов конструктора) и создание диалогового окна: Для модального диалога Для немодального диалога
    вызов конструктора с параметром, указывающим ID шаблона диалогавызов конструктора без параметра шаблона диалога
    вызов метода DoModalвызов метода Create с параметром, указывающим ID шаблона диалога
  • переопределение метода OnInitDialog и включение в него вызова метода базового класса и необходимых действий по инициализации диалогового окна.



  • Класс CDialog предоставляет следующие конструкторы объекта:

    CDialog (LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL); CDialog (UINT nIDTemplate, CWnd* pParentWnd = NULL); CDialog ();

    Параметр lpszTemplateName - это строка, содержащая имя ресурса шаблона диалога, nIDTemplate - значение ID ресурса шаблона диалога. По умолчанию редактор ресурсов присваивает шаблонам диалога идентификаторы, начинающиеся с префикса IDD_. Параметр pParentWnd задает указатель на родительское окно или окно собственник (типа CWnd), которому принадлежит этот диалог. Значение NULL показывает, что родительским окном является главное окно приложения.

    Конструктор без параметров используется для создания модального окна диалога на основе шаблона, расположенного в памяти. При этом применяется метод InitModalIndirect. Для создания модального диалога после вызова конструктора следует вызвать метод DoModal.

    Класс CDialog предоставляет следующие методы Create для создания немодального диалога:

    BOOL Create (LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL); BOOL Create (UINT nIDTemplate, CWnd* pParentWnd = NULL);

    При успешном завершении создания диалогового окна и инициализации эти методы возвращают ненулевое значение.

    Если в шаблоне диалога не установлен стиль WS_VISIBLE, то для отображения диалога необходимо вызвать метод ShowWindow.

    Класс CDialog предоставляет большой набор методов, предназначенных для работы с диалоговым окном, включая следующие:

  • DoModal - используется для создания модального диалогового окна.
  • NextDlgCtrl - перемещает фокус на следующий элемент управления диалогового окна (а с последнего элемента управления - на первый).
  • PrevDlgCtrl - перемещает фокус на предыдущий элемент управления диалогового окна (а с первого элемента управления - на последний);
  • GotoDlgCtrl (CWnd* pWndCtrl) - перемещает фокус на указываемый параметром pWndCtrl элемент управления (чтобы получить значение параметра pWndCtrl, можно вызвать метод CWnd::GetDlgItem).
  • SetDefID (UINT nID) - изменяет командную кнопку, используемую по умолчанию (параметр задает ID командной кнопки).
  • SetHelpID (UINT nIDR) - определяет контекстно-зависимый идентификатор справки (ID) для диалогового окна.
  • EndDialog - используется для закрытия модального диалогового окна.
  • OnInitDialog - вызывается для обработки сообщения WM_INITDIALOG, которое инициируется при выполнении методов Create, CreateIndirect или DoModal.При переопределении этого метода первоначально должен быть вызван метод OnInitDialog базового класса. При успешном завершении метод возвращает значение TRUE.
  • OnSetFont (CFont* pFont) - определяет шрифт, используемый по умолчанию для всех элементов управления диалогового окна.
  • OnOK - обработчик сообщения, вызываемый при щелчке пользователя на командной кнопке OK (с идентификатором IDOK).
  • OnCancel - обработчик сообщения, вызываемый при щелчке пользователя на командной кнопке Cancel (с идентификатором IDCANCEL).


  • Класс CFileDialog

    Класс CFileDialog инкапсулирует поведение диалогов Open и Save As. Для работы с объектом типа CFileDialog сначала следует создать этот объект, используя конструктор, а затем управлять данным компонентом через поля структуры m_ofn типа OPENFILENAME.
    Структура OPENFILENAME содержит информацию, используемую функциями GetOpenFileName и GetSaveFileName для инициализации диалогов Open или Save As .
    Структура OPENFILENAME имеет следующее определение:
    typedef struct tagOFN { DWORD lStructSize; // Длина структуры в байтах HWND hwndOwner; // Дескриптор окна владельца // данного диалога или NULL HINSTANCE hInstance; LPCTSTR lpstrFilter; // Указатель на буфер, содержащий // пары null-ограниченных строк: // первая строка - это описание // фильтра (например: "Программы"), // вторая строка - шаблон // (например: "*.exe;*.com")" LPTSTR lpstrCustomFilter; DWORD nMaxCustFilter; DWORD nFilterIndex; LPTSTR lpstrFile; // Указатель на буфер, // который содержит // имя файла, используемое для // инициализации поля File Name, // или NULL. При успешном завершении // функции GetOpenFileName или //GetSaveFileName поле содержит // логический диск, путь и имя // выбранного файла. DWORD nMaxFile; LPTSTR lpstrFileTitle; // Указатель на буфер, // содержащий имя и расширение выбранного файла DWORD nMaxFileTitle; LPCTSTR lpstrInitialDir; // Указатель на null- // ограниченную строку, которая представляет каталог, // используемый для инициализации диалога LPCTSTR lpstrTitle; DWORD Flags; WORD nFileOffset; WORD nFileExtension; LPCTSTR lpstrDefExt; LPARAM lCustData; LPOFNHOOKPROC lpfnHook; LPCTSTR lpTemplateName; #if (_WIN32_WINNT >= 0x0500) void * pvReserved; DWORD dwReserved; DWORD FlagsEx; #endif // (_WIN32_WINNT >= 0x0500) } OPENFILENAME, *LPOPENFILENAME;
    Листинг 19.2.
    Если метод DoModal, используемый для отображения диалога типа CFileDialog, возвращает значение IDOK, то для получения информации об имени файла можно использовать методы члены класса CFileDialog.
    Если предполагается разрешить пользователю одновременно выбрать более одного файла, то до вызова метода DoModal следует установить флаг OFN_ALLOWMULTISELECT.

    Например:

    OPENFILENAME ofn; // Данные для диалога char szFile[260]; // Буфер для имени файла HWND hwnd; // Окно - владелец отображаемого диалога HANDLE hf; // Дексриптор файла // Инициализация структуры OPENFILENAME ZeroMemory(&ofn, sizeof(OPENFILENAME)); // Макрос, // заполняющий нулями указанный блок памяти ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = "Все\0*.*\0Текстовые\0*.TXT\0"; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; // Отображение диалога Open if (GetOpenFileName(&ofn)==TRUE) hf = CreateFile(ofn.lpstrFile, GENERIC_READ, 0, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);

    Класс CFileDialog содержит поле m_ofn, которое является структурой типа OPENFILENAME, используемой для инициализации диалогов Open и Save As.

    Для создания данного диалога применяется следующий конструктор:

    CFileDialog( BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL, DWORD dwSize = sizeof( OPENFILENAME ));

    Параметр bOpenFileDialogопределяет типа создаваемого диалога: значение TRUE указывает диалог Open, а FALSE - диалог Save As. Параметр lpszDefExt указывает используемое по умолчанию расширение файла. Если пользователь не вводит расширение файла в поле File name, то данное значение автоматически добавляется к имени файла. Если значение этого параметра равно NULL, то расширение не добавляется. Параметр lpszFileName - это NULL или имя файла, отображаемое при открытии данного диалога. Параметр dwFlags определяет флажки, используемые для настройки диалога; lpszFilter - это пары строк, определяющие фильтры для выбора файлов. При использовании структуры типа OPENFILENAME строки фильтра следует ограничивать символом '\0', а в данном параметре следует использовать символ |.


    Параметр pParentWnd- это указатель на окно владелец или родительское окно данного диалога. Размер структуры OPENFILENAME указывается параметром dwSize.

    Например:

    void CMyDlg::OnFileOpen() { // szFilters - строка с описанием и шаблоном фильтров char CMyDlg::szFilters[]= "Текстовые файлы (*.txt)|*.my|Все файлы(*.*)|*.*||"; // Создание диалога Open, использующего // для отображаемых файлов расширение txt CFileDialog fileDlg = new CFileDialog (TRUE, "txt", "*.txt", OFN_FILEMUSTEXIST| OFN_HIDEREADONLY, szFilters, this); if( fileDlg.DoModal ()==IDOK ) // Отображение диалога { CString pathName = fileDlg.GetPathName(); CString fileName = fileDlg.GetFileTitle (); } }

    Отображение диалога стандартного Open также можно выполнить вызовом метода GetOpenFileName.

    Например:

    if (GetOpenFileName(&ofn)==TRUE) hf = CreateFile(ofn.lpstrFile, GENERIC_READ, 0, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);

    Классы диалогов библиотеки MFC

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

    MFC-приложения

    MFC-приложения можно реализовывать как:
  • однодокументные приложения (Single document);
  • многодокументные приложения (Multiple documents);
  • приложения-диалоги (Dialog based).

  • Тип создаваемого приложения выбирается на странице Application type мастера создания MFC-приложения (рис. 19.1).
    MFC-приложения
    Рис. 19.1.  Страница Application Тype мастера создания MFC-приложения
    Черты пользовательского интерфейса для создаваемого диалога выбираются на страницах User Interface Features (рис.19.2) и Advanced Features (рис. 19.3) мастера создания MFC-приложения.
    MFC-приложения
    Рис. 19.2.  Страница User Interface Features мастера создания MFC-приложения
    MFC-приложения
    Рис. 19.3.  Страница Advanced Features мастера создания MFC-приложения

    Приложения-диалоги

    Базовым классом любого Windows-приложения, основанного на оконном интерфейсе, является класс cWinApp.
    При создании приложения-диалога мастер построения MFC-приложения добавляет в проект два класса:
  • класс приложения, производный от cWinApp;
  • класс диалога, производный от CDialog.

  • Класс приложения имеет следующее объявление и реализацию:
    // Заголовочный файл class CD1App : public CWinApp {public: CD1App(); public: virtual BOOL InitInstance(); // Первый // выполняемый метод // Implementation DECLARE_MESSAGE_MAP() }; extern CD1App theApp; // Переменная - приложение // Файл реализации D1.cpp #include "stdafx.h" #include "D1.h" #include "D1Dlg.h" // CD1App BEGIN_MESSAGE_MAP(CD1App, CWinApp) // Обрабатываемые события ON_COMMAND(ID_HELP, &CWinApp::OnHelp) END_MESSAGE_MAP() CD1App::CD1App(){ } // Конструктор CD1App theApp; BOOL CD1App::InitInstance() { CWinApp::InitInstance(); AfxEnableControlContainer(); SetRegistryKey(_T("Local AppWizard-Generated Applications")); CD1Dlg dlg; // Создание объекта диалога m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal(); // Отображение // диалога if (nResponse == IDOK) { } else if (nResponse == IDCANCEL) { } return FALSE; // Завершение приложения }
    Класс диалога имеет следующее объявление и реализацию:
    // Заголовочный файл class CD1Dlg : public CDialog {public: CD1Dlg(CWnd* pParent = NULL); // Конструктор enum { IDD = IDD_D1_DIALOG }; // Ресурс диалога protected: // Поддержка DDX/DDV: virtual void DoDataExchange(CDataExchange* pDX); // Реализация protected: HICON m_hIcon;
    // Функции таблицы обрабатываемых событий virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() }; // Файл реализации D1Dlg.cpp #include "stdafx.h" #include "D1.h" #include "D1Dlg.h" class CAboutDlg : public CDialog // Класс // вспомогательного диалога {public: CAboutDlg(); enum { IDD = IDD_ABOUTBOX }; // Ресурс диалога protected: virtual void DoDataExchange(CDataExchange* pDX); protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX);} BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP() // Класс окна диалога приложения CD1Dlg::CD1Dlg(CWnd* pParent /*=NULL*/) : CDialog(CD1Dlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CD1Dlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CD1Dlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() END_MESSAGE_MAP() // Методы обработки событий BOOL CD1Dlg::OnInitDialog() { CDialog::OnInitDialog(); ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); // Указатель // на системное меню if (pSysMenu != NULL) // Добавление пунктов к { CString strAboutMenu; //системному меню strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } SetIcon(m_hIcon, TRUE); // Определение крупной // пиктограммы SetIcon(m_hIcon, FALSE); // Определение мелкой пиктограммы return TRUE; } void CD1Dlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } void CD1Dlg::OnPaint() { CDialog::OnPaint(); }

    HCURSOR CD1Dlg::OnQueryDragIcon() // Запрос курсора { return static_cast(m_hIcon); }

    Листинг 19.1.

    Для отображения окна диалога следует:

  • создать ресурс диалога, имеющий конкретный вид диалогового окна, и разместить в нем требуемые элементы управления (каждый элемент управления также определяется своим идентификатором ресурса);
  • создать класс, наследуемый от класса CDialog (или производного от него), и связать создаваемый класс с ресурсом диалога.


  • Связывание командных кнопок с методами - обработчиками событий и идентификаторов ресурсов элементов управления с переменными выполняется в редакторе ресурсов.

    Для назначения кнопке метода обработчика события можно выполнить на ней двойной щелчок мышью (для события BN_CLICKED) или выделить элемент управления и выполнить команду контекстного меню Add Event Handler.

    По умолчанию для командной кнопки, выполняющей завершение диалога, будет вставлен следующий метод - обработчик события:

    void CD1Dlg::OnBnClickedOk() { OnOK(); // OnOK - метод базового класса CDialog }

    Имя метода - обработчика события формируется из префикса On, имени события и идентификатора элемента управления.

    Обработчик события добавляется как новый член класса диалога.

    При добавлении каждого нового метода обработчика события в таблицу сообщений также добавляется новый вход.

    Таблица сообщений (иногда называемая также таблицей событий) указывается между макросами BEGIN_MESSAGE_MAP иEND_MESSAGE_MAP. Макрос BEGIN_MESSAGE_MAP имеет два параметра - имя класса, обрабатывающего данные сообщения, и имя базового класса. Чтобы определить, что данный класс имеет таблицу сообщений, в заголовочном файле указывается макрос DECLARE_MESSAGE_MAP.

    Например:

    BEGIN_MESSAGE_MAP(CD1Dlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDOK, &CD1Dlg::OnBnClickedOk) END_MESSAGE_MAP()

    Каждый вход таблицы сообщений содержит имя события (например, ON_BN_CLICKED), идентификатор ресурса элемента управления (например, IDOK) и имя метода - обработчика события (например, &CD1Dlg::OnBnClickedOk).


    Диалог может быть создан как:

  • модальный диалог, завершение которого необходимо выполнить до продолжения работы с приложением (диалог отображается вызовом метода DoModal);
  • немодальный диалог, позволяющий получать одновременный доступ к другим немодальным диалогам данного приложения (диалог создается вызовом метода Create и сразу отображается, если установлен стиль диалога WS_VISIBLE).


  • Для того чтобы отобразить созданный диалог как модальный, следует создать объект диалога и выполнить для него метод DoModal().

    Например:

    CD1Dlg dlg; INT_PTR nResponse = dlg.DoModal();

    Если предполагается определить диалог как главное окно приложения, то необходимо для объекта приложения установить значение свойства m_pMainWnd (CWnd* m_pMainWnd;).

    Например:

    CD1Dlg dlg; m_pMainWnd = &dlg; // AfxGetApp()->m_pMainWnd // AfxGetApp() возвращает для // приложения указатель на // объект типа CWinApp INT_PTR nResponse = dlg.DoModal();

    Для модального диалога следует проверять код завершения диалога.

    Например:

    INT_PTR nResponse = dlg.DoModal(); if (nResponse == IDOK) { } else if (nResponse == IDCANCEL) { }

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

    Например:

    CMyDialog* pDialog; // Указатель на объект диалога void CMyWnd::OnSomeAction() { // pDialog может быть инициализирован как NULL // в конструкторе или классе CMyWnd pDialog = new CMyDialog(); if(pDialog != NULL) { BOOL ret = pDialog->Create(IDD_MYDIALOG,this); // Параметр // указывает используемый ресурс диалога if(!ret) AfxMessageBox("Ошибка при создании диалога"); pDialog->ShowWindow(SW_SHOW); } else AfxMessageBox("Ошибка с объектом диалога"); }

    Создание приложений на С++ в Visual Studio .NET

    Среда Visual Studio .NET позволяет создавать приложения с использованием различных библиотек:
  • библиотеки MFC для С++, предоставляющей широкий набор классов для создания SDI- и MDI-приложений, а также приложений, реализующих работу с базами данных, и серверных WEB-приложений;
  • библиотеки активных шаблонов ATL;
  • библиотеки .NET Framework, используемой при разработке приложений управляемого кода. Эта библиотека может применяться как для приложений управляемого кода на С++, так и для создания приложения на языках C# и Visual Basic.


  • Стандартные диалоги

    Класс CCommonDialog - это базовый класс, инкапсулирующий поведение стандартных диалогов Windows. Библиотека MFC содержит классы стандартных диалогов, производных от CCommonDialog, включая следующие:
  • CFileDialog
  • CFontDialog
  • CColorDialog
  • CPageSetupDialog
  • CPrintDialog
  • CPrintDialogEx
  • CFindReplaceDialog
  • COleDialog

  • Для использования класса CCommonDialog следует подключить заголовочный файл afxdlgs.h.

    Введение в программирование

    Архитектура "документ-отображение"

    Для реализации SDI и MDI-приложений посредством библиотеки классов MFC применяется механизм "документ/отображение". Это позволяет отображать один документ различными способами.

    Документы и отображения

    Архитектура "документ/отображение" (document/view) базируется на взаимодействии четырех основных классов.
  • Класс CDocument (или COleDocument ) реализует основные возможности внутреннего представления документа. Этот класс используется для управления данными (обычно документ представляет модуль данных, открываемых по команде Open и сохраняемых командой Save меню File).
  • Класс CView (или один из его наследуемых классов) отвечает за отображение содержания документа или любой графической информации. Объекты этого класса будем называть отображениями. Одному документу может быть сопоставлено несколько различных объектов отображений. При этом отображение пристыковывается или сопоставляется документу.

  • Отображение представляет вид документа на экране и является некоторой средой, взаимосвязывающей документ и пользователя. Объект "отображение" воспроизводит вид документа на экране и интерпретирует действия пользователя как операции над документом. Класс отображения также форматирует изображение как для печати, так и для предварительного просмотра.
  • Класс CFrameWnd (или другой класс Windows-окна, включая MDIFrameWnd и CMDIChildWnd) представляют объекты, обеспечивающие окно-рамку (frame) вокруг одного или нескольких отображений документа.
  • Класс CDocTemplate (или классы CSingleDocTemplate, CMultiDocTemplate) поддерживают объект шаблона документа, координирующий один или несколько существующих документов заданного типа, и управляют созданием документа, отображения и окна-рамки для этого типа.

  • Документы и отображения
    Рис. 20.1.  Взаимосвязь объектов "документ ->отображение -> окно-рамка "
    Объект "отображение" используется не только для представления документов на экране. Он же представляет документ и для печати, и для предварительного просмотра печатаемого документа.
    С помощью механизма "документ-отображение" реализуется разделение данных, их экранное представление и обработка действий пользователя.
    Операции по изменению данных реализуются классами документа.
    Объект отображение только вызывает этот интерфейс для доступа и обновления данных.

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

    Создание нового документа и сопоставленного ему отображения и окна-рамки. выполняется различными объектами: объектом "приложение", шаблоном документа, созданным документом и созданным окном-рамкой.

    Следующая таблица иллюстрирует, какими объектами создаются шаблон документа, документ, окно-рамка и отображение.

    Создающий объектСоздаваемый объект
    Приложение (Application object)Шаблон документа
    Шаблон документа (Document template)Документ
    Шаблон документа (Document template)Окно-рамка
    Окно-рамка (Frame window)Отображение (View)
    Все оконные MFC-приложения имеют как минимум два объекта: объект "приложение", производный от класса CWinApp, и объект "главное окно", производный от класса CWnd или его потомков - классов CFrameWnd, CMDIFrameWnd и CDialog.

    Объект "документ" отвечает за внутреннее представление данных, показываемых объектом "отображене". Объект "отображение" предназначен для манипулирования данными объекта документа. Объект "отображение" состыковывается с объектом "документ" и окном-рамкой, образуя цепочку "документ->отображение->окно". Приложения, использующие SDI (Single Document Interface) или MDI (Multi Document Inter-face) интерфейс соответственно, называются SDI-приложением и MDI-приложением. Такие приложения относятся к приложениям с архитектурой "документ-отображение" (document/view).

    включает также код класса CAboutDlg

    // App1.cpp : Файл реализации класса приложения // ( включает также код класса CAboutDlg для диалога About) // Таблица сообщений класса CApp1App BEGIN_MESSAGE_MAP(CApp1App, CWinApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout) ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) END_MESSAGE_MAP() CApp1App::CApp1App() { } // Конструктор CApp1App theApp; // Объект приложение BOOL CApp1App::InitInstance() // Первый выполняемый метод //приложения { CWinApp::InitInstance(); // Регистрация шаблонов документа CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( // Строка //описания шаблона IDR_MAINFRAME, RUNTIME_CLASS(CApp1Doc), RUNTIME_CLASS(CMainFrame), // Главное окно // SDI приложения RUNTIME_CLASS(CApp1View)); AddDocTemplate(pDocTemplate);

    m_pMainWnd->ShowWindow(SW_SHOW); // Отображение // главного окна приложения m_pMainWnd->UpdateWindow(); return TRUE; } // Класс CAboutDlg, реализующий диалог About class CAboutDlg : public CDialog {public: CAboutDlg(); enum { IDD = IDD_ABOUTBOX }; // Идентификатор ресурса диалога protected: virtual void DoDataExchange(CDataExchange* pDX); protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX);} BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) // Таблица сообщений END_MESSAGE_MAP() void CApp1App::OnAppAbout() // Обработчик команды меню About { CAboutDlg aboutDlg; aboutDlg.DoModal(); // Отображение модального диалога } // App1Doc.cpp : файл реализации класса документа CApp1Doc IMPLEMENT_DYNCREATE(CApp1Doc, CDocument) BEGIN_MESSAGE_MAP(CApp1Doc, CDocument) // Таблица сообщений END_MESSAGE_MAP() CApp1Doc::CApp1Doc() {} CApp1Doc::~CApp1Doc() { } BOOL CApp1Doc::OnNewDocument() // Переопределение метода, { // вызываемого при открытии документа if (!CDocument::OnNewDocument()) return FALSE; // Место для добавления кода инициализации документа return TRUE; } void CApp1Doc::Serialize(CArchive& ar) // Сериализация { if (ar.IsStoring()) { // Место для добавления кода сохранения } else { // Место для добавления кода загрузки } } // App1View.cpp : файл реализации класса CApp1View IMPLEMENT_DYNCREATE(CApp1View, CView) BEGIN_MESSAGE_MAP(CApp1View, CView) // Таблица сообщений ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP() CApp1View::CApp1View() { } CApp1View::~CApp1View() { } BOOL CApp1View::PreCreateWindow(CREATESTRUCT& cs) { return CView::PreCreateWindow(cs); } void CApp1View::OnDraw(CDC* /*pDC*/) { CApp1Doc* pDoc = GetDocument(); // Указатель на документ ASSERT_VALID(pDoc); } BOOL CApp1View::OnPreparePrinting(CPrintInfo* pInfo) { return DoPreparePrinting(pInfo); // Действие по умолчанию } void CApp1View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { } void CApp1View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { } // MainFrm.cpp : файл реализации класса CMainFrame IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //Таблица сообщений ON_WM_CREATE() END_MESSAGE_MAP() static UINT indicators[] = { ID_SEPARATOR, // Идентификаторы ресурсов ID_INDICATOR_CAPS, // для строки состояния ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; CMainFrame::CMainFrame() { } CMainFrame::~CMainFrame() { } // Обработчик сообщения, получаемого при создания окна int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; return 0; } BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; return TRUE; }

    Листинг 20.1.
    Закрыть окно





    // App1.cpp : Файл реализации класса приложения

    // ( включает также код класса CAboutDlg для диалога About)

    // Таблица сообщений класса CApp1App

    BEGIN_MESSAGE_MAP(CApp1App, CWinApp)

    ON_COMMAND(ID_APP_ABOUT, OnAppAbout)

    ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)

    ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)

    ON_COMMAND(ID_FILE_PRINT_SETUP,

    CWinApp::OnFilePrintSetup)

    END_MESSAGE_MAP()

    CApp1App::CApp1App() { } // Конструктор

    CApp1App theApp; // Объект приложение

    BOOL CApp1App::InitInstance() // Первый выполняемый метод //приложения

    { CWinApp::InitInstance();

    // Регистрация шаблонов документа

    CSingleDocTemplate* pDocTemplate;

    pDocTemplate = new CSingleDocTemplate( // Строка

    //описания шаблона

    IDR_MAINFRAME,

    RUNTIME_CLASS(CApp1Doc),

    RUNTIME_CLASS(CMainFrame), // Главное окно

    // SDI приложения

    RUNTIME_CLASS(CApp1View));

    AddDocTemplate(pDocTemplate);

    m_pMainWnd->ShowWindow(SW_SHOW); // Отображение

    // главного окна приложения

    m_pMainWnd->UpdateWindow();

    return TRUE;

    }

    // Класс CAboutDlg, реализующий диалог About

    class CAboutDlg : public CDialog

    {public:

    CAboutDlg();

    enum { IDD = IDD_ABOUTBOX }; // Идентификатор ресурса диалога

    protected:

    virtual void DoDataExchange(CDataExchange* pDX);

    protected:

    DECLARE_MESSAGE_MAP()

    };

    CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { }

    void CAboutDlg::DoDataExchange(CDataExchange* pDX)

    { CDialog::DoDataExchange(pDX);}

    BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) // Таблица сообщений

    END_MESSAGE_MAP()

    void CApp1App::OnAppAbout() // Обработчик команды меню About

    { CAboutDlg aboutDlg;

    aboutDlg.DoModal(); // Отображение модального диалога

    }

    // App1Doc.cpp : файл реализации класса документа CApp1Doc

    IMPLEMENT_DYNCREATE(CApp1Doc, CDocument)

    BEGIN_MESSAGE_MAP(CApp1Doc, CDocument) // Таблица сообщений

    END_MESSAGE_MAP()

    CApp1Doc::CApp1Doc() {}

    CApp1Doc::~CApp1Doc() { }

    BOOL CApp1Doc::OnNewDocument() // Переопределение метода,

    { // вызываемого при открытии документа

    if (!CDocument::OnNewDocument())

    Класс CDocTemplate

    Класс CDocTemplate является абстрактным классом, предоставляющим основные возможности для работы с шаблонами документов.
    Шаблон документа определяет отношение между тремя типами классов.
  • Класс документа, наследуемый отCDocument.
  • Класс отображения, выполняющий показ данных для указанного класса документа. Класс отображения может быть наследован от классов CView, CScrollView, CFormView, CEditView. (Класс CEditView может быть использован и напрямую.)
  • Класс окна-рамки, содержащий отображение. Для SDI-приложений этот класс наследуется от базового класса CFrameWnd, а для MDI-приложений - от базового класса CMDIChildWnd. Однако, если в приложении не требуется переопределять поведение объекта "окно-рамка", то может быть создан объект "окно-рамка" непосредственно базового класса, без объявления производных классов.

  • Для каждого типа документа в приложении создается отдельный шаблон документа.
    Класс CDocTemplate является абстрактным классом и, следовательно, не может использоваться непосредственно для создания объектов. Обычно для создания шаблонов применяются его производные классы CSingleDocTemplate и CMultiDocTemplate. Однако можно создать и свой собственный производный класс шаблона документа.
    Например:
    BEGIN IDR_MYTYPE "\nSheet\nWorksheet\n Worksheets (*.myc)\n.myc\ n MyCalcSheet\nMyCalc Worksheet" END BOOL CMyApp::InitInstance() { CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_MYTYPE, RUNTIME_CLASS(CMyDoc), RUNTIME_CLASS(CMDIChildWnd), RUNTIME_CLASS(CMyView)); AddDocTemplate(pDocTemplate); // ... }

    Класс CDocument

    Класс CDocument предоставляет основные возможности управления документами.
    Класс CDocument поддерживает набор стандартных операций над документом: создание, загрузка, сохранение.
    Каждый документ содержит указатель на сопоставленный ему объект шаблона документа - для каждого типа документа; свой шаблон.
    Пользователи взаимодействуют с документом посредством объекта отображение (наследуемого от класса Cview - или его производных классов), ассоциированного с документом.
    Для работы с документами в приложении следует:
  • создать производный класс от класса CDocument для каждого типа документа;
  • добавить переменные члены класса для хранения данных каждого документа;
  • реализовать методы - члены класса, выполняющие чтение и изменение данных документа.


  • Класс CFormView

    Класс CFormView является базовым классом, используемым для отображений, которые содержат элементы управления. Процесс создания отображения CFormView аналогичен созданию диалогового окна.
    Для того чтобы использовать отображение CFormView, следует:
  • разработать в редакторе ресурсов шаблон диалогового окна;
  • создать класс отображения. Например:
    CMyFormView::CMyFormView() : CFormView( CMyFormView::IDD );
  • Переопределить метод OnUpdate;
  • реализовать методы, выполняющие внесение изменений из отображения в документ;
  • сопоставить класс отображения с классом документа и окном-рамкой, используя шаблон документа.


  • Класс CMultiDocTemplate

    Класс CMultiDocTemplate определяет шаблон документа для MDI-приложений: одновременно может быть открыто несколько документов; главное окно используется как пространство, в котором можно открывать несколько окон-рамок для отображения документов.

    Класс CSingleDocTemplate

    Класс CSingleDocTemplate определяет шаблон документа для SDI-приложений: одновременно может быть открыт только один документ; документ отображается в главном окне. Как правило, SDI-приложения поддерживают только один тип документа и, соответственно, имеют только один объект CSingleDocTemplate.

    Класс CView

    Класс CView реализует основные возможности для работы с отображениями. Отношения между классом отображения, классом окна-рамки и классом документа устанавливаются объектом CDocTemplate. Вызов конструктора нового отображения и сопоставление его документу выполняется при открытии пользователем нового окна или при разделении существующего окна.
    Один объект "отображение" может быть сопоставлен только одному документу, однако один документ может иметь несколько сопоставленных ему отображений.
    Отображения обрабатывают сообщения, зафиксированные в таблице сообщений.
    Отображения выполняют только показ данных документа и не отвечают за сохранение данных. Документ предоставляет отображению необходимую информацию о данных посредством вызова объектом "отображение" методов документа. Для инициализации отображения, сопоставленного документу, следует вызвать метод OnInitialUpdate .
    Для внесения изменений в данные отображение, как правило, вызывает метод CDocument::UpdateAllViews, который инициирует вызов методов OnUpdate для всех других отображений. По умолчанию реализация метода OnUpdateопределяет всю клиентскую область как недостоверную. Этот метод может быть переопределен.
    Для того чтобы использовать класс отображений Cview, следует:
  • объявить производный класс от Cview;
  • реализовать метод OnDraw, выполняющий отображение экрана или вывод на печать.

  • В классе View объявлены методы для реализации архитектуры "документ-отображение", включая следующие:
  • DoPreparePrinting - метод вызывается из переопределяемого метода OnPreparePrinting для отображения диалогового окна Print и создания контекста устройства принтера.
  • GetDocument - метод возвращает указатель на объект "документ", сопоставленный данному отображению, или NULL, если отображение не пристыковано ни к какому документу;
  • OnActivateView - метод вызывается при активации или деактивации отображения;
  • OnActivateFrame - метод вызывается при активации или деактивации окна-рамки, содержащего отображение;
  • OnUpdate - вызов этого метода инициируется при изменении отображения документа.


  • Классы отображений

    Для вывода данных на различные графические устройства используются классы отображений. Базовым классом всех таких классов является класс Cview, производный от класса CWnd.
    Библиотека MFC, кроме класса Cview, предоставляет широкий набор классов отображения, наследуемых от CView, включая следующие классы:
  • CScrollView - для автоматической прокрутки и масштабирования отображения.
  • CFormView - для отображения форм, содержащих элементы управления. Объект CFormView создается на основе ресурса диалога.
  • CCtrlView - базовый класс для классов CEditView, CTreeView, CListView, CEditView и CRichEditView. Эти классы позволяют использовать архитектуру "документ-отображение" для некоторых элементов управления Windows.
  • CEditView - для отображения, реализующего свойства поля редактирования. Объект класса CEditView реализует работу простого текстового редактора.
  • CRichEditView - для отображения, содержащего объект CRichEditCtrl. Этот класс отображения реализует свойства окна редактирования и позволяет управлять форматированием текста.
  • CListView - для отображения, содержащего объект ClistCtrl.
  • CTreeView - для отображения, содержащего объект CtreeCtrl.
  • CHtmlView - для отображения, использующего WEB-броузер. Данный класс позволяет просматривать Internet-страницы и папки локальной файловой системы, а также может быть использован как контейнер для активного документа.
  • CRecordView и CDaoRecordView - для отображения форм, которые содержат элементы управления, связанные с полями объекта CRecordset или CDaoRecordset, что отображают таблицы баз данных.
  • COleDBRecordView - для отображения форм, которые содержат элементы управления, связанные с полями объекта CRowset. Этот класс применяется для доступа к данным средств OLE DB.


  • Реализация интерфейса пользователя

    Классы отображений содержат набор методов, которые выполняют обработку событий, инициированных пользователем. Переопределение этих методов позволяет задавать:
  • обработку сообщений Windows от мыши и от клавиатуры;
  • обработку выполнения пунктов меню, нажатия кнопок инструментария и клавиш-акселераторов.

  • Реализация интерфейса пользователя может включать в себя обработку:
  • определяемых пользователем пунктов меню;
  • пунктов меню, определяющих стандартные действия, такие как Edit|Copy, Edit|Cut и Edit|Paste.

  • MFC поддерживает реализацию трех типов интерфейса для отображения одного документа посредством нескольких отображений:
  • Отображение объектов одного класса в отдельных окнах документа (поддержка команды Window| New).
    Реализация интерфейса пользователя

  • Отображение объектов одного класса в одном разделенном окне документа (поддержка команды Window|Split). Создается несколько объектов отображения одного класса.
    Реализация интерфейса пользователя

  • Отображение объектов различных классов в одном окне документа.
    Реализация интерфейса пользователя


  • Поддержка работы с разделенным окном реализована в классе CSplitterWnd.Разделенным окном является обычное окно, разбитое на несколько панелей (окон) и содержащее один и тот же документ.
    Цикл жизни документа (а совместно с ним - и окна-рамки, и отображения) в MDI-приложении состоит из:
  • вызова конструктора документа;
  • вызова метода OnNewDocument или OnOpenDocument для каждого нового документа;
  • отображения и обработки документа;
  • удаления данных вызовом метода DeleteContents;
  • вызова деструктора документа.

  • Цикл жизни документа (а совместно с ним - и окна-рамки и отображения) в SDI-приложении отличается тем, что вызов конструктора происходит только один раз при первоначальном создании документа; аналогично и проходит вызов деструктора. А для каждого повторно создаваемого или открываемого документа выполняются только этапы 2-3-4.

    Сериализация данных

    Библиотека MFC реализует модель обмена данными между документом и файлом через специальный объект, называемый архивом. Обмен данными между приложением и архивом называется сериализацией. Для обмена используется метод Serialize класса документа.
    При создании шаблона приложения с помощью мастера AppWizard можно добавить меню File, содержащее пункты Open, Save и Save as. Для обработки каждого из указанных пунктов меню, AppWizard вставляет в программный код класса документа (производного от CDocument) переопределяемый метод Serialize - либо для чтения состояния документа из архива, либо для записи (загрузки) состояния документа в архив. Программисту необходимо только вставить в метод Serialize код, выполняющий запись переменных в архив и чтение переменных из архива.
    Для использования средств сериализации следует включить в объявление и реализацию класса макросы DECLARE_SERIAL и IMPLEMENT_SERIAL соответственно.

    Создание приложения с архитектурой "документ-отображение"

    При создании приложения, использующего архитектуру "документ-отображение", как правило, должны быть выполнены следующие шаги:
  • созданы ресурсы, используемые в шаблоне документа;
  • реализован класс приложения (производный от CWinApp). Переопределен в этом классе метод InitInstance;
  • в методе InitInstance созданы шаблоны всех типов используемых документов и добавлены в список шаблонов. Класс CWinApp имеет переменную "член класса m_pDocManager", используемую для доступа к списку шаблонов;
  • в методе InitInstance создан объект "окно-рамка" класса, наследуемого от класса CMDIFrameWnd или CMDIChildWnd, и данное окно отображено как главное окно приложения;
  • в таблицу сообщений добавлены входы, которые описывают обработку сообщений, поступающих при открытии или сохранении файла;
  • создан объект "приложение";
  • реализован класс документа, производный от CDocument. Переопределены методы OnNewDocument и Serialize;
  • реализован класс окна-рамки, производный от CMDIFrameWnd или CMDIChildWnd;
  • реализован класс отображения, производный от CView или его потомков.


  • Создание SDI-приложения

    Начинать разработку приложения следует с формирования "макета" приложения, который автоматически формируется мастером приложений AppWizard.
    Мастер приложений MFC Application Wizardпозволяет создавать следующие шаблоны для приложений с архитектурой "документ-отображение":
  • Single document - приложения с SDI-интерфейсом.
  • Multiple documents - приложения с MDI-интерфейсом, поддерживающие только одно окно верхнего уровня.

  • Мастер приложений позволяет последовательно формировать шаблон SDI приложения (Single Document Interface), включая или не включая в него поддержку таких элементов, как: доступ к информации из баз данных, реализация возможностей контейнера или сервера, применение OLE, использование элементов ActiveX, а также реализацию встроенной панели инструментов, строки состояния, некоторых пунктов меню.
    Так, при формировании SDI приложения будут созданы следующие классы:
  • производный класс от класса приложения CApp;
  • класс рамки окна;
  • класс документа (производный от CDocument);
  • класс отображения (производный от CView).

  • Далее приводится код основных фрагментов SDI-приложения, автоматически создаваемого мастером MFC Application Wizard.
    // App1.cpp : Файл реализации класса приложения // (включает также код класса CAboutDlg для диалога About) // Таблица сообщений класса CApp1App BEGIN_MESSAGE_MAP(CApp1App, CWinApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout) ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) END_MESSAGE_MAP() CApp1App::CApp1App() { } // Конструктор CApp1App theApp; // Объект приложение BOOL CApp1App::InitInstance() // Первый выполняемый метод //приложения { CWinApp::InitInstance(); // Регистрация шаблонов документа CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( // Строка //описания шаблона IDR_MAINFRAME, RUNTIME_CLASS(CApp1Doc), RUNTIME_CLASS(CMainFrame), // Главное окно // SDI приложения RUNTIME_CLASS(CApp1View)); AddDocTemplate(pDocTemplate);
    m_pMainWnd->ShowWindow(SW_SHOW); // Отображение // главного окна приложения m_pMainWnd->UpdateWindow(); return TRUE; } // Класс CAboutDlg, реализующий диалог About class CAboutDlg : public CDialog {public: CAboutDlg(); enum { IDD = IDD_ABOUTBOX }; // Идентификатор ресурса диалога protected: virtual void DoDataExchange(CDataExchange* pDX); protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX);} BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) // Таблица сообщений END_MESSAGE_MAP() void CApp1App::OnAppAbout() // Обработчик команды меню About { CAboutDlg aboutDlg; aboutDlg.DoModal(); // Отображение модального диалога } // App1Doc.cpp : файл реализации класса документа CApp1Doc IMPLEMENT_DYNCREATE(CApp1Doc, CDocument) BEGIN_MESSAGE_MAP(CApp1Doc, CDocument) // Таблица сообщений END_MESSAGE_MAP() CApp1Doc::CApp1Doc() {} CApp1Doc::~CApp1Doc() { } BOOL CApp1Doc::OnNewDocument() // Переопределение метода, { // вызываемого при открытии документа if (!CDocument::OnNewDocument()) return FALSE; // Место для добавления кода инициализации документа return TRUE; } void CApp1Doc::Serialize(CArchive& ar) // Сериализация { if (ar.IsStoring()) { // Место для добавления кода сохранения } else { // Место для добавления кода загрузки } } // App1View.cpp : файл реализации класса CApp1View IMPLEMENT_DYNCREATE(CApp1View, CView) BEGIN_MESSAGE_MAP(CApp1View, CView) // Таблица сообщений ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP() CApp1View::CApp1View() { } CApp1View::~CApp1View() { } BOOL CApp1View::PreCreateWindow(CREATESTRUCT& cs) { return CView::PreCreateWindow(cs); } void CApp1View::OnDraw(CDC* /*pDC*/) { CApp1Doc* pDoc = GetDocument(); // Указатель на документ ASSERT_VALID(pDoc); } BOOL CApp1View::OnPreparePrinting(CPrintInfo* pInfo) { return DoPreparePrinting(pInfo); // Действие по умолчанию } void CApp1View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { } void CApp1View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { } // MainFrm.cpp : файл реализации класса CMainFrame IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //Таблица сообщений ON_WM_CREATE() END_MESSAGE_MAP() static UINT indicators[] = { ID_SEPARATOR, // Идентификаторы ресурсов ID_INDICATOR_CAPS, // для строки состояния ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; CMainFrame::CMainFrame() { } CMainFrame::~CMainFrame() { } // Обработчик сообщения, получаемого при создания окна int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; return 0; } BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; return TRUE; }
    Листинг 20.1.
    Создание SDI-приложения

    Управление документом

    Для реализации управления данными документа первоначально необходимо выполнить следующие шаги:
  • Для каждого типа документов объявить класс, производный от класса CDocument.
  • Для хранения данных объявить переменные класса документа.
  • Переопределить в производном классе документа метод Serializeкласса CDocument. Метод Serialize реализует чтение и запись данных документа с диска.
  • Для выполнения стандартных операций над документом следует дополнительно переопределить методы базового класса, такие как OnNewDocument, OnOpenDocument и DeleteContents.

  • Данные документа хранятся в переменных класса документа. Библиотека MFC содержит ряд классов, инкапсулирующих работу с различными наборами данных, включая следующие классы:
  • CString
  • CObList
  • CByteArray
  • CStringList
  • CMapWordToPrt

  • Для выполнения операций над элементами данных в класс документа добавляются требуемые методы.
    При создании объекта "отображение" формируется указатель на документ, используемый отображением для доступа к объекту "документ" (его методам и переменным). Этот указатель может быть получен объектом отображения вызовом метода GetDocument класса CView. Отображение использует данные, хранимые в классе документа, для их отображения и изменения.

    Введение в программирование

    Элементы управления

    Библиотека MFC содержит широкий набор классов элементов управления. Элементы управления, отображаемые любым окном, предварительно должны быть добавлены в ресурс диалога. Это выполняется в редакторе ресурсов среды проектирования Visual Studio .NET.
    Все оконные элементы управления наследуются от класса CWnd. На следующей схеме представлен список классов элементов управления, наследуемых от CWnd.
    Элементы управления

    В окне Resource View все ресурсы каждого проекта отображаются в виде иерархического дерева с узлами, соответствующими типам используемых ресурсов. В каждом узле расположены ресурсы одного типа. Так, узел Dialog содержит все ресурсы-диалоги, используемые в приложении.
    Каждый ресурс имеет свой идентификатор ресурса, используемый функциями библиотеки MFC для доступа к данному ресурсу.

    Класс CAnimateCtrl

    Класс CAnimateCtrl предоставляет функции управления анимацией в среде Windows.
    Элемент управления, созданный как экземпляр данного класса, является объектом анимации. Такой объект представляет из себя обычное окно, в котором отображается некоторый клип, являющийся файлом в формате AVI (Audio Video Interleaved). AVI-файл содержит последовательный набор битовых изображений. Объекты анимации могут показывать только простые AVI-клипы.

    Класс CButton

    Класс CButton применяется для работы со следующими элементами управления:
  • командная кнопка;
  • флажок;
  • радиокнопка (переключатель).

  • Элемент управления "кнопка", называемый также командная кнопка, как правило, используется для обработки сообщения BN_CLICKED.
    Свойство Default Button позволяет указать командную кнопку, устанавливаемую как кнопка по умолчанию: нажатие пользователем клавиши Enter интерпретируется как щелчок на данной кнопке.
    Свойство Icon позволяет указать, что вместо текста будет отображена пиктограмма (стиль BS_ICON).
    Свойство Bitmap позволяет указать, что вместо текста будет отображено изображение (стиль BS_BITMAP).
    Свойство Multiline используется в том случае, если текст слишком длинный, чтобы уместиться на кнопке в одну строку.
    Для работы с элементом управления "кнопка" следует использовать класс CButton.
    Элемент управления "флажок Check Box" может иметь два или три состояния: включенное, выключенное или неопределенное (необязательно).
    Кроме возможности связывания флажка с объектом типа CButton, флажок можно связать с переменной типа BOOL.
    Свойство Auto позволяет создавать элемент управления, переключение состояний (включен/выключен) которого происходит автоматически при щелчке мышью.
    Свойство Tri-state используется для создания элемента управления "флажок", имеющего три состояния. Одновременно с состояниями "включен" или "выключен", используется состояние "неопределен", в котором флажок выглядит "посеревшим". Если значение свойства Push Like установлено равным True, то создается элемент управления "флажок", отображаемый как командная кнопка: при нажатии флажок имеет вид вдавленной кнопки, а при ненажатом состоянии - выпуклой.
    Свойство Flat определяет, будет ли создаваемый элемент управления иметь вид плоской кнопки.
    Элемент управления "радиокнопка" (Radio Button) аналогичен флажку, но не может иметь неопределенного состояния. Также при объединении несколько радиокнопок в группу только одна из них может иметь включенное состояние.

    Кроме возможности связывания флажка с объектом типа CButton, радиокнопку можно связать с переменной типа BOOL.

    При использовании класса CButton тип кнопки можно определить ее стилем, указываемым в методе Create при создании кнопки. Класс CButton наследуется классом CBitmapButton, реализующим кнопки с изображениями вместо текста.

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

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

    Если же объект был создан динамически вызовом метода new, то для его разрушения следует вызвать метод delete.

    Класс CButton предоставляет ряд методов, включая следующие:

  • Create - метод создает Windows-кнопку для объекта CButton и при успешном завершении возвращает ненулевое значение. При вызове метода кнопке могут быть присвоены следующие флажки стиля (оконного объекта):
  • WS_CHILD - устанавливается всегда;
  • WS_VISIBLE - видимая кнопка;
  • WS_DISABLED - недоступная кнопка;
  • WS_GROUP - используется для образования групп кнопок: устанавливается для первой кнопки группы;
  • WS_TABSTOP - устанавливается для включения кнопки в табулированный порядок.


  • GetCheck - метод определяет состояние кнопки (флажка или радиокнопки), созданной как BS_AUTOCHECKBOX, BS_AUTORADIOBUTTON, BS_AUTO3STATE, BS_CHECKBOX, BS_RADIOBUTTON, BS_3STATE, и возвращает одно из следующих значений:
  • 0 - кнопка не включена (не отмечена);
  • 1 - кнопка включена (отмечена);
  • 2 - кнопка находится в неопределенном состоянии (только для кнопок, имеющих флажки стиля BS_3STATE или BS_AUTO3STATE).


  • Для командных кнопок метод возвращает значение 0.
  • GetState - метод определяет текущее состояние кнопки. Возвращаемое значение формируется как комбинация набора значений, выделяемых с помощью следующих масок:
  • 0x0003 - определяет состояние кнопки-флажка или радиокнопки:
  • 0 - кнопка не включена (не отмечена);
  • 1 - кнопка отмечена;
  • 2 - состояние кнопки не определено.
  • 0x0004 - определяет состояние выделения кнопки: при значении 0 - кнопка не нажата (пользователь щелкнул на ней левой кнопкой мыши и держит ее);
  • 0x0008 - определяет фокус: при значении 1 - кнопка находится в фокусе.


  • SetBitmap- метод "растровое изображение, отображаемое на данной кнопке".

    Например:

    CButton myButton; // Создание кнопки с изображением myButton.Create(_T("Кнопка 1"), WS_CHILD|WS_VISIBLE|BS_BITMAP, CRect(10,10,60,50), pParentWnd, 1); myButton.SetBitmap( ::LoadBitmap(NULL, MAKEINTRESOURCE(OBM_CHECK)) );
  • SetButtonStyle - метод изменяет стиль кнопки.
  • SetCheck - метод устанавливает новое состояние кнопки-переключателя или радиокнопки.


  • Класс CComboBox

    Класс CComboBox реализует функционирование комбинированного окна, иногда также называемого комбинированным окном списка.
    Комбинированное окно представляет собой элемент управления, объединяющий окно списка с окном редактирования или со статическим элементом управления. Окно списка при этом может иметь как распахнутое (отображаемое постоянно), так и свернутое состояние (отображаемое только при щелчке пользователя на стрелке вниз).
    Выбранный элемент списка отображается в окне редактирования или в окне статического элемента управления.
    Метод GetLBText определяет строку текста, соответствующую указанному индексу элемента окна списка комбинированного окна. Метод GetCurSel возвращает индекс выделенного элемента окна списка комбинированного окна. Если выделенного элемента нет, то метод возвращает значение CB_ERR.
    Например:
    extern CComboBox* pmyComboBox; // Выбор следующего элемента в окне комбинированного списка // после текущего элемента int nIndex = pmyComboBox->GetCurSel(); // Индекс текущего // элемента int nCount = pmyComboBox->GetCount(); // Всего элементов // в списке if ((nIndex != CB_ERR) && (nCount > 1)) { if (++nIndex < nCount) pmyComboBox->SetCurSel(nIndex); else pmyComboBox->SetCurSel(0); }

    Класс CEdit

    Класс CEdit обеспечивает функционирование элемента управления "окно редактирования", называемое также текстовым полем. Окно редактирования может быть как однострочным, так и многострочным. Иногда однострочное окно редактирования также называют полем ввода.
    Для создания многострочного окна редактирования следует установить значение свойства Multilin равным True. Для установки разбиения на строки с использованием мягкого конца строки следует установить свойство Auto HScroll.
    При мягком конце строки, в отличие от жесткого, окно редактирования отображает разделение на строки, не вставляя непосредственно в сам текст символы конца строки и перевода каретки.
    При двойном щелчке мыши на элементе управления выполняется автоматическая вставка метода обработчика сообщения OnEnChangeEdit.
    Таблица сообщений родительского окна может содержать для элемента управления "окно редактирования" вызовы следующих стандартных обработчиков сообщений:
  • ON_EN_CHANGE - пользователь изменил текст в окне редактирования.
  • ON_EN_ERRSPACE - недостаточно памяти.
  • ON_EN_HSCROLL - пользователь щелкнул на горизонтальной линейке прокрутки окна редактирования.
  • ON_EN_KILLFOCUS - окно редактирование теряет фокус.
  • ON_EN_MAXTEXT - текущая позиция вставки превысила указанное для окна редактирования число символов; либо не установлен стиль ES_AUTOHSCROLL, а число вставляемых символов превышает ширину окна редактирования или общее число строк превышает высоту окна редактирования.
  • ON_EN_SETFOCUS - окно редактирования получает фокус ввода.
  • ON_EN_UPDATE - пользователь изменил текст в окне редактирования; (а в чем отличие от п.2? - Ред.)
  • ON_EN_VSCROLL - пользователь щелкнул на вертикальной линейке прокрутки окна редактирования.

  • Класс CEdit предоставляет широкий набор методов для работы с окном редактирования, включая следующие:
  • CanUndo - метод возвращает ненулевое значение, если последнее изменение в окне редактирования можно отменить, и 0 - если изменение отменить нельзя.
  • CharFromPos- метод возвращает номер символа в строке и строки (начиная с 0) для символа, наиболее близко расположенного к указанной параметром точке.
  • Clear - метод удаляет в окне редактирования текущее выделение текста.
  • Copy - метод копирует текущее выделение текста из окна редактирования в буфер промежуточного хранения.
  • Cut - метод удаляет текущее выделение текста из окна редактирования и копирует его в буфер промежуточного хранения.
  • Paste - метод выполняет вставку данных из буфера промежуточного хранения в текущую позицию окна редактирования.
  • GetFirstVisibleLine - метод возвращает номер первой отображаемой строки в окне редактирования.
  • GetLine - метод копирует указанную строку текста (без нулевого символа) из окна редактирования в буфер и при успешном завершении возвращают количество скопированных байтов.
  • GetLineCount - метод возвращает количество строк текста в многострочном окне редактирования.

    Например:

    extern CEdit* pmyEdit; int i, nLineCount = pmyEdit->GetLineCount(); CString strText, strLine; for (i=0;i < nLineCount;i++) { // Получение длины строки i int len = pmyEdit->LineLength(pmyEdit->LineIndex(i)); pmyEdit->GetLine(i, strText.GetBuffer(len), len); strText.ReleaseBuffer(len); strLine.Format(TEXT("line %d: '%s'\n"), i, strText); cout<< strLine; }
  • GetSel - метод определяет позицию первого и последнего символа выделенного фрагмента текста.

    Например:

    extern CEdit* pmyEdit; // Выделить все символы, следующие за текущим // выделенным фрагментом DWORD dwSel = pmyEdit->GetSel(); // Определение // позиций текущего выделения pmyEdit->SetSel(HIWORD(dwSel), -1); // HIWORD(dwSel) - // позиция первого невыделенного символа, // следующего за выделением

  • LimitText - метод устанавливает максимально допустимую длину (в байтах) вводимого пользователем текста.
  • LineIndex - метод возвращает номер первого символа в указанной строке, а при значении параметра, равном -1 - номер первого символа в текущей строке.
  • LineLength - метод возвращает длину строки.
  • ReplaceSel - метод выполняет замену выделенного фрагмента текста на указанную строку.
  • SetPasswordChar - метод устанавливает символ, отображаемый при вводе пароля, вместо любого вводимого пользователем символа.
  • SetSel - метод выполняет выделение в окне редактирования указанного фрагмента текста.


  • Класс CListBox

    Элемент управления List Box "окно списка", называемый иногда просто списком, используется для работы с информацией, отображаемой в виде списка. Окно списка может быть реализовано как список с единичным или с множественным выбором.
    Окно списка можно связать как с переменной типа CString, так и с объектом класса CListBox.
    Свойство Selection позволяет устанавливать тип списка:
  • Single (по умолчанию) - пользователь может выделить только один элемент списка
  • Multiple - пользователь может одновременно выделить несколько элементов списка. Выделение элементов (или снятие выделения) осуществляется при щелчке или двойном щелчке мыши.
  • Extended - пользователь может одновременно выделить несколько элементов списка. Выделение элементов (или снятие выделения) осуществляется перемещением мыши при нажатой кнопке.
  • None - пользователь не может выделить ни одного элемента списка.

  • Класс CListBox предоставляет широкий набор методов для работы со списком, включая следующие:
  • GetCount - метод возвращает количество элементов в окне списка.
  • SetTopIndex - метод прокручивает окно списка к указанному элементу, отображая его первым видимым элементом.

  • Например:
    extern CListBox* pmyListBox; // Определение первым видимым элементом списка // элемента,расположенного посередине списка pmyListBox->SetTopIndex(pmyListBox->GetCount()/2);
  • GetText- метод возвращает строку по указанному индексу элемента списка.
    Например:
    extern CListBox* pmyListBox; CString str, str2; int n; for (int i=0;i < pmyListBox->GetCount();i++) { n = pmyListBox->GetTextLen( i ); pmyListBox->GetText( i, str.GetBuffer(n) ); str.ReleaseBuffer(); // Дампинг всех элементов списка (#ifdef _DEBUG ) str2.Format(_T("item %d: %s\r\n"), i, str.GetBuffer(0)); afxDump << str2; }
  • SetCurSel- метод выделяет указанный элемент списка и при необходимости прокручивает окно списка так, чтобы выделенный элемент стал видимым.
  • GetSelCount - метод возвращает общее количество выделенных элементов в окне списка с множественным выбором.
  • AddString - метод добавляет в окно списка новый элемент, содержащий указанную строку.
  • DeleteString - метод удаляет из окна списка строку с соответствующим индексом.
  • InsertString - метод вставляет в указанное место окна списка новый элемент, содержащий заданную строку.
  • FindString - метод выполняет поиск указанной строки в окне списка.
  • ResetContent - метод удаляет все элементы окна списка.


  • Класс CRichEditCtrl

    Элемент управления "окно расширенного редактирования" (rich edit control) позволяет пользователю не только редактировать текст, в отличие от элемента управления "окно редактирования", но также выполнять форматирование символов и абзацев, встраивать OLE-объекты.
    Данный элемент управления обеспечивает программный интерфейс для форматирования текста, при этом в приложении должны быть реализованы все компоненты интерфейса пользователя, делающие доступными сами операции форматирования.
    Метод GetDefaultCharFormat позволяет получить атрибуты форматирования символов по умолчанию. Атрибуты форматирования символов определяются в структуре типа CHARFORMAT, а атрибуты форматирования абзаца задаются в структуре типа PARAFORMAT. Метод GetLine копирует в буфер указанную строку текста.
    Методы SetDefaultCharFormat и SetSelectionCharFormat позволяют установить атрибуты форматирования символов, используемые по умолчанию или для выделенного фрагмента текста соответственно. Класс CRichEditCtrl

    Класс CStatic

    Класс CStatic реализует работу со статическим текстом (меткой). Этот элемент управления предназначается для отображения различных надписей и не может непосредственно редактироваться пользователем. Содержание элемента управления Static Box определяется на этапе проектирования свойством Caption и в дальнейшем может изменяться только программным путем.
    Выполнить связывание элемента управления "статический текст" можно с переменной типа CString или объектом класса CStatic.
    Свойство Border определяет, что вокруг элемента управления будет отображаться рамка.
    Свойство Transparent определяет, является ли фон элемента прозрачным.

    Работа с элементами управления

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

  • Если элемент управления не требуется изменять в процессе выполнения приложения, то для него можно не выполнять связывание с объектом или с переменной.
    Все элементы управления, встраиваемые в диалоговые окна, можно подразделить на общие и ActiveX-элементы управления. Библиотека MFC поддерживает как те, так и другие, инкапсулируя их свойства и поведение в соответствующих классах.
    Инициализацию элементов управления можно выполнять в методе OnInitDialog класса диалога.
    Чтобы изменять значения, отображаемые элементами управления, или использовать значения, определяемые посредством действий пользователя, приложению нужно иметь доступ к элементам управления.
    Доступ к элементам управления может быть реализован различными способами:
  • элемент управления связывается с некоторой переменной;
  • элемент управления связывается с объектом соответствующего класса, и для работы с ним используются методы этого класса;
  • элемент управления не связывается ни с каким объектом, а для доступа к нему используется его идентификатор (отображаемый на странице свойств);
  • переменная, инициируемая указателем на элемент управления. Указатель на элемент управления можно получить вызовом метода CWnd::GetDlgItem с заданным в качестве параметра идентификатора элемента управления.

  • Например:
    // 1. Инициализация указателем: CEdit* pEdit1 = (CEdit*) GetDlgItem(IDC_EDIT1); // Конструкция pMyStat-> Metod() позволяет вызывать // любые методы класса // 2.
    Доступ по идентификатору: SetDlgItemText(IDC_EDIT1, L"12345");

    Для связывания элемента управления с переменной или объектом соответствующего класса можно использовать диалог Add Member Variable Wizard (рис. 21.4), вызываемый командой контекстного меню Add Variable.

    Работа с элементами управления
    Рис. 21.4.  Диалог Add Member Variable

    Флажок Control variable определяет способ использования создаваемой переменной:

  • при установленном флажке связь будет осуществляться с объектом соответствующего класса;
  • при снятом флажке устанавливается связь с переменной и обмен данными выполняется DDX-методами, автоматически добавляемыми в переопределяемый метод DoDataExchange. Метод DoDataExchange вызывается методом UpdateData, указывающим в качестве параметра направление обмена данными: из переменной в элемент управления или наоборот.


  • Редактор ресурсов

    В редакторе ресурсов диалога можно выполнить настройку внешнего вида и поведение диалога, а также всех элементов управления, расположенных в нем.
    Для задания значений свойств и указания используемых обработчиков событий в редакторе ресурсов используется окно свойств Properties. Оно состоит из двух страниц: страницы свойств и страницы событий (рис. 21.1). Каждая станица отображается как четыре вертикально расположенных области. В первой верхней области расположен список имен объектов, содержащий идентификаторы всех используемых для данного диалога элементов управления, включая и идентификатор ресурса диалога.
    Редактор ресурсов
    Рис. 21.1.  Окно свойств редактора ресурсов — страницы Properties и Events
    Под списком имен объектов расположена панель инструментов, содержащая кнопки: для выбора типа просмотра свойств (по категориям или в алфавитном порядке), переключения между страницей свойств Properties, страницей событий для элементов управления Control Events и страницей сообщений Messages (только для диалога).
    В следующей области располагается панель значений - страница Properties или страница Control Events. В нижней части окна свойств Properties расположено поле, отображающее текущий выделенный элемент страницы свойств или страницы событий.
    На странице событий представлены идентификаторы всех элементов управления диалога и список допустимых для каждого элемента управления сообщений. Если обработчик сообщения создан, то в поле справа от имени сообщения указывается имя метода - обработчика данного сообщения.
    При создании посредством окна свойств нового метода - обработчика события в заголовочный файл будет добавлено объявление нового метода - обработчика события, в файл реализации вставлен код описания метода, а в таблицу сообщений - новый вход для данного сообщения.
    Доступные элементы управления отображаются в редакторе ресурсов в окне Toolbox . Для того чтобы расположить элемент управления в диалоге, достаточно выделить этот компонент на вкладке Dialog Editor окна Toolbox , а затем щелкнуть мышью в требуемом месте разрабатываемого диалогового окна.
    В шаблон диалога можно встроить любой элемент управления, расположенный в окне Toolbox (рис. 21.2).

    Редактор ресурсов
    Рис. 21.2.  Панель элементов управления

    Вкладка Dialog Editor окна Toolbox содержит кнопки для следующих элементов управления (сверху вниз):

  • Pointer - курсор, используемый для выбора элементов управления в шаблоне диалога.
  • Button - кнопка.
  • Check Box - флажок.
  • Edit Control - текстовое поле.
  • Combo Box - окно комбинированного списка.
  • List Box - окно списка.
  • Group Box - рамка группы кнопок.
  • Radio Button - радиокнопка.
  • StaticText - статический текст.
  • Picture Control - рисунок.
  • Horizontal Scroll Bar - горизонтальная линейка прокрутки.
  • Vertical Scroll Bar - вертикальная линейка прокрутки.
  • Slider Control - маркер (слайдер).
  • Spin Control - элемент прокрутки.
  • Progress Control - шкала индикации.
  • Hot Key - определение клавиш-акселераторов.
  • List Control - список.
  • Tree Control - элемент управления дерево.
  • Tab Control - вкладка.
  • Animation Control - элемент управления анимация.
  • Rich Edit 2.0 Control - окно редактирования с элементами форматирования.
  • Date Time Picker - определение данных в формате даты и времени.
  • Month Calendar Control - календарь.
  • IP Address Controls - определение IP-адреса.
  • Extended Combo Box - комбинированный список с поддержкой изображений.
  • Custom Control - настраиваемый элемент управления.


  • Список отображаемых элементов управления в окне Toolbox можно редактировать. Для этого следует выполнить команду меню Tools | Choose Toolbox Items и выбрать добавляемые элементы управления (рис. 21.3).

    Редактор ресурсов
    Рис. 21.3.  Диалог Choose Toolbox Items

    Введение в программирование

    Класс CImageList

    Класс CImageList реализует работу со списком одноразмерных изображений. Его непосредственным базовым классом является класс CObject.
    Методы класса CImageList позволяют более эффективно управлять наборами больших и малых пиктограмм и наборами изображений.
    Все изображения списка изображений хранятся в одном битовом массиве в экранном формате. Дополнительно список изображений может включать монохромный битовый массив, который содержит маску, используемую для отображения изображений с прозрачным фоном.
    Пиктограммы всегда содержат маску для отображения с прозрачным фоном.
    Создание объекта "список изображений" выполняется в два этапа.
  • Вызывается конструктор класса CImageList.
  • Вызывается метод Create, создающий список изображений и пристыковывающий его к объекту CImageList.

  • Например:
    extern CImageList* pmyImageList; pmyImageList->Create(32, 32, // Размер изображения ILC_COLOR16, // 16-битовый цвет 0, // Первоначальное количество изображений 4);
    Класс CImageList предоставляет ряд переменных и методов, включая следующие:
  • m_hImageList - указатель списка изображений, сопоставленного данному объекту.
  • Create - конструктор объекта.
  • Attach - метод пристыковывает указанный список изображений к объекту типа CImageList.
  • Add - метод используется для добавления нового изображения к списку изображений.
    Например:
    extern CImageList* pmyImageList; // Добавление к списку изображений двух пиктограмм pmyImageList->Add(AfxGetApp()->LoadIcon(IDI_ICON1)); pmyImageList->Add(AfxGetApp()->LoadIcon(IDI_ICON2)); // Добавление изображения, в котором все черные // пиксели устанавливаются прозрачными CBitmap bm; bm.LoadBitmap(IDB_BITMAP1); pmyImageList->Add(&bm, RGB(0, 0, 0));
  • Replace - метод используется для удаления изображения из списка изображений.

  • Класс CImageList

    Класс CPropertySheet

    Класс CPropertySheet инкапсулирует возможности управления многостраничным диалогом.
    Класс CPropertySheet предоставляет ряд методов, включая следующие:
  • GetActiveIndex - метод возвращает индекс текущей страницы свойств.
  • GetPageCount - метод возвращает количество страниц свойств в окне набора свойств.
  • GetPage - метод возвращает указатель на страницу свойств, заданную по индексу.
  • GetActivePage - метод возвращает указатель на текущую активную страницу свойств.
  • SetActivePage - метод устанавливает новую текущую активную страницу.
    Например:
    BOOL CMySheet::OnInitDialog() // Класс CMySheet //наследует от CPropertySheet { BOOL bResult = CPropertySheet::OnInitDialog(); CFrameWnd* frame = (CFrameWnd*) AfxGetMainWnd(); CPSheetDoc* doc = (CPSheetDoc*) frame->GetActiveDocument(); SetActivePage(doc->m_LastActivePage); // Устанавливаем // текущей последнюю активную страницу return bResult; } BOOL CMyPropertySheet::OnCommand(WPARAM wParam, LPARAM lParam) { if (LOWORD(wParam) == IDOK) { CFrameWnd* frame = (CFrameWnd*) AfxGetMainWnd(); CPSheetDoc* doc = (CPSheetDoc*)frame->GetActiveDocument(); // Сохранение индекса последней активной страницы: doc->m_LastActivePage = GetPageIndex(GetActivePage()); // Или GetActiveIndex() } return CPropertySheet::OnCommand(wParam, lParam); }
  • SetTitle - метод устанавливает заголовок для окна набора свойств;
  • GetTabControl - метод возвращает указатель на объект класса CTabCtrl, обеспечивая доступ к элементу управления "вкладка".
  • SetFinishText - метод устанавливает текст, отображаемый на командной кнопке Finish, и делает ее доступной.
  • SetWizardButtons - метод устанавливает доступные командные кнопки для мастера, которые задаются комбинацией следующих флажков: PSWIZB_BACK, PSWIZB_NEXT, PSWIZB_FINISH, PSWIZB_DISABLEDFINISH.
  • SetWizardMode - метод устанавливает, что окно набора свойств будет мастером (при отображении окна вызовом метода DoModal возвращаемые значения будут ID_WIZFINISH или IDCANCEL).
    Например:
    CPropertySheet dlg; CPropertyPage page1, page2; dlg.AddPage(&page1); dlg.AddPage(&page2); dlg.SetWizardMode(); dlg.DoModal();
  • AddPage - метод добавляет в окно набора свойств указанную страницу свойств;
  • RemovePage - метод удаляет указанную страницу свойств из окна набора свойств;
  • PressButton - метод имитирует выбор в окне набора свойств указанной командной кнопки.


  • Класс PRopertyPage

    Объекты класса CPropertyPage представляют отдельные страницы набора свойств.
    Непосредственным базовым классом для СPropertyPage является класс CDialog.
    Класс CPropertyPage предоставляет ряд методов, включая следующие:
  • CancelToClose - метод вызывается для замены кнопки OK на кнопку Close.
  • SetModified - метод делает командную кнопку Apply доступной или недоступной.
  • QuerySiblings - метод используется для передачи сообщения другим страницам набора свойств.
  • OnCancel - метод вызывается средой выполнения при щелчке пользователя на командной кнопке Cancel.
  • OnKillActive - метод вызывается средой выполнения при смене текущей активной страницы свойств.
  • OnOK - метод вызывается средой выполнения при щелчке пользователя на командной кнопке OK.
  • OnSetActive - метод вызывается средой выполнения при выборе пользователем новой активной текущей страницы.
  • OnApply - метод вызывается средой выполнения при щелчке пользователя на командных кнопках OK или Apply.
  • OnWizardFinish - метод вызывается средой выполнения при щелчке пользователя на командной кнопке Finish.


  • Создание многостраничных диалогов

    Многостраничные диалоги отображаются как:
  • окна наборов свойств (property sheets);
  • диалоговые окна со вкладками (tab dialog boxes);
  • мастера, представляющие собой последовательность страниц свойств.

  • Примером мастеров могут служить мастера AppWizard, используемые для создания шаблона приложения. Для управления последовательностью страниц в мастерах используются кнопки Back, Next, Finish и Cancel. Чтобы создать окно набора свойств как мастер, следует перед вызовом метода DoModal вызвать метод SetWizardMode, а для доступа к командным кнопкам использовать метод SetWizardButtons.
    Многостраничный диалог может быть реализован с помощью класса CPropertySheet, производного от CWnd. Объект класса CPropertySheet называется набором свойств или окном набора свойств.
    Каждая страница из набора свойств может быть реализована объектом типа CPropertyPage, производного от CDialog.
    Диалоговое окно класса CPropertyPage называется страницей свойств.
    Окно набора свойств представляет собой специальный вид диалогового окна, используемый для изменения атрибутов некоторого внешнего объекта.
    Окно набора свойств состоит из трех частей:
  • диалогового окна;
  • одной или нескольких страниц свойств, показываемых попеременно;
  • компонента "вкладка", содержащего заголовки вкладок для каждой страницы.

  • Для того чтобы использовать в приложении многостраничный диалог, нужно выполнить следующие шаги:
  • Создать в редакторе ресурсов шаблон диалога отдельно для каждой страницы свойств.
    Шаблоны диалогов могут иметь различный размер - при размещении окна набора свойств будет выбран размер наибольшего шаблона диалога.
    На странице свойств окна Properties для каждого шаблона диалога следует установить значения для свойств
  • Caption - содержит заголовок вкладки, отображаемый для текущей страницы;
  • Style - имеет значение Child;
  • Border - указывает стиль рамки Thin;
  • Titlebar - установлено равным True;
  • Disabled - установлено равным True.
  • Создать для каждого шаблона диалога класс, производный от CPropertyPage, и добавить в эти классы переменные-члены класса, используемые для доступа к странице свойств.
    Для каждой добавляемой в набор свойств страницы создать по одному объекту класса, производного от CpropertyPage
  • Создать в коде программы объект класса CPropertySheet. Вызвать для каждой страницы (типа производного от CPropertyPage) метод CPropertySheet::AddPage.
  • Показать окно набора свойств, вызвав метод CPropertySheet::DoModal или CPropertySheet::Create.


  • Чтобы выполнить обмен данными с окном набора свойств, следует создать переменные для доступа к элементам управления страниц свойств и использовать DDX- и DDV-методы для обмена данными между элементами управления и переменными класса окна страницы свойств.

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

    Например:

    void CMyView::DoModalPropertySheet() // Создание // модального окна { // набора свойств с двумя страницами CPropertySheet propsheet; // Создание объекта "диалог" CMyPage1 page1; // Создание объекта класса, // производного от CPropertyPage CMyPage2 page2; //... page1.m_nMember1 = m_nMember1; // Обмен данными: page1.m_nMember2 = m_nMember2; // инициализация page2.m_strMember3 = m_strMember3; // переменных членов //класса propsheet.AddPage(&page1); // Добавление страницы свойств propsheet.AddPage(&page2); //... if (propsheeet.DoModal() == IDOK) { m_nMember1 = page1.m_nMember1; m_nMember2 = page1.m_nMember2; m_strMember3 = page2.m_strMember3; GetDocument()->SetModifiedFlag(); GetDocument()->UpdateAllViews(NULL); } }

    Введение в программирование

    Подключение используемых пространств имен using

    namespace D1 { // Подключение используемых пространств имен using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Windows::Forms; using namespace System::Data; using namespace System::Drawing; // ref class объявляет управляемый класс C++ public ref class Form1 : public System::Windows::Forms::Form { public: Form1(void){InitializeComponent();} protected: ~Form1(){if (components) {delete components;}} // Объявление элемента управления "кнопка": private: System::Windows::Forms::Button^ button1; // Объявление элемента управления // "поле ввода": private: System::Windows::Forms::TextBox^ textBox1; // Объявление контейнера private:System::ComponentModel::Container ^components;

    #pragma region Windows Form Designer generated code // Формируется дизайнером формы void InitializeComponent(void) { // Создание объекта "кнопка": this->button1 = (gcnew System::Windows::Forms::Button()); // Создание объекта "поле ввода": this->textBox1 = (gcnew System::Windows::Forms::TextBox()); this->SuspendLayout(); // Временно // приостанавливает события компоновки до // вызова метода ResumeLayout или // Задание свойств для кнопки button1 this->button1->Location = System::Drawing::Point(427, 22); this->button1->Name = L"button1"; this->button1->Size = System::Drawing::Size(75, 23); this->button1->TabIndex = 0; this->button1->Text = L"button1"; this->button1->UseVisualStyleBackColor = true; // Определение обаботчика события Click для кнопки this->button1->Click += gcnew System::EventHandler( this, &Form1::button1_Click); // Задание свойств для поля ввода textBox1 this->textBox1->Location = System::Drawing::Point(80, 25); this->textBox1->Name = L"textBox1"; this->textBox1->Size = System::Drawing::Size(100, 20); this->textBox1->TabIndex = 1; // Задание свойств для формы Form1 this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(548, 266); ..// Добавление в форму элементов управления this->Controls->Add(this->textBox1); this->Controls->Add(this->button1); this->Name = L"Form1"; this->Text = L"Form1"; this->ResumeLayout(false); this->PerformLayout(); } #pragma endregion // Обработчик события для кнопки private: System::Void button1_Click( System::Object^ sender, System::EventArgs^ e) {this->textBox1->Text = L"123456"; } }; // Конец реализации класса } // Конец пространства имен D1

    Листинг 23.1.
    Закрыть окно





    namespace D1 {

    // Подключение используемых пространств имен

    using namespace System;

    using namespace System::ComponentModel;

    using namespace System::Collections;

    using namespace System::Windows::Forms;

    using namespace System::Data;

    using namespace System::Drawing;

    // ref class объявляет управляемый класс C++

    public ref class Form1 :

    public System::Windows::Forms::Form

    {

    public:

    Form1(void){InitializeComponent();}

    protected:

    ~Form1(){if (components) {delete components;}}

    // Объявление элемента управления "кнопка":

    private: System::Windows::Forms::Button^ button1;

    // Объявление элемента управления

    // "поле ввода":

    private: System::Windows::Forms::TextBox^ textBox1;

    // Объявление контейнера

    private:System::ComponentModel::Container ^components;

    #pragma region Windows Form Designer generated code

    // Формируется дизайнером формы

    void InitializeComponent(void)

    { // Создание объекта "кнопка":

    this->button1 =

    (gcnew System::Windows::Forms::Button());

    // Создание объекта "поле ввода":

    this->textBox1 =

    (gcnew System::Windows::Forms::TextBox());

    this->SuspendLayout(); // Временно

    // приостанавливает события компоновки до

    // вызова метода ResumeLayout или

    // Задание свойств для кнопки button1

    this->button1->Location =

    System::Drawing::Point(427, 22);

    this->button1->Name = L"button1";

    this->button1->Size = System::Drawing::Size(75, 23);

    this->button1->TabIndex = 0;

    this->button1->Text = L"button1";

    this->button1->UseVisualStyleBackColor = true;

    // Определение обаботчика события Click для кнопки

    this->button1->Click += gcnew System::EventHandler(

    this,

    &Form1::button1_Click);

    // Задание свойств для поля ввода textBox1

    this->textBox1->Location =

    System::Drawing::Point(80, 25);

    this->textBox1->Name = L"textBox1";

    this->textBox1->Size =

    System::Drawing::Size(100, 20);

    this->textBox1->TabIndex = 1;

    Clean up any resources being

    namespace D_1 {partial class Form1 { private System.ComponentModel.IContainer components = null; /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); }

    #region Windows Form Designer generated code

    /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.button1 = new System.Windows.Forms.Button(); this.textBox1 = new System.Windows.Forms.TextBox(); this.SuspendLayout(); // Элемент управления button1 this.button1.Location = new System.Drawing.Point(188,27); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(75, 23); this.button1.TabIndex = 0; this.button1.Text = "button1"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // Элемент управления textBox1 this.textBox1.Location = new System.Drawing.Point(42, 30); this.textBox1.Name = "textBox1"; this.textBox1.Size = new System.Drawing.Size(100, 20); this.textBox1.TabIndex = 1; // Окно формы Form1 this.AutoScaleDimensions = // Определяет размер // окна как ширина и высота (тип float) new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(292, 266); this.Controls.Add(this.textBox1); this.Controls.Add(this.button1); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); this.PerformLayout(); // Заставляет элемент // управления выполнить для всех дочерних // элементов компановку в соответствии // с их свойствами } #endregion // Объявление переменных private System.Windows.Forms.Button button1; private System.Windows.Forms.TextBox textBox1; } }

    Листинг 23.2.
    Закрыть окно





    namespace D_1

    {partial class Form1

    {

    private System.ComponentModel.IContainer

    components = null;

    ///

    /// Clean up any resources being used.

    ///

    /// true if managed resources should be disposed; otherwise, false.

    protected override void Dispose(bool disposing)

    { if (disposing && (components != null))

    { components.Dispose(); }

    base.Dispose(disposing);

    }

    #region Windows Form Designer generated code

    ///

    /// Required method for Designer support - do not modify

    /// the contents of this method with the code editor.

    ///

    private void InitializeComponent()

    {

    this.button1 = new System.Windows.Forms.Button();

    this.textBox1 = new System.Windows.Forms.TextBox();

    this.SuspendLayout();

    // Элемент управления button1

    this.button1.Location =

    new System.Drawing.Point(188,27);

    this.button1.Name = "button1";

    this.button1.Size = new System.Drawing.Size(75, 23);

    this.button1.TabIndex = 0;

    this.button1.Text = "button1";

    this.button1.UseVisualStyleBackColor = true;

    this.button1.Click +=

    new System.EventHandler(this.button1_Click);

    // Элемент управления textBox1

    this.textBox1.Location =

    new System.Drawing.Point(42, 30);

    this.textBox1.Name = "textBox1";

    this.textBox1.Size =

    new System.Drawing.Size(100, 20);

    this.textBox1.TabIndex = 1;

    // Окно формы Form1

    this.AutoScaleDimensions = // Определяет размер

    // окна как ширина и высота (тип float)

    new System.Drawing.SizeF(6F, 13F);

    this.AutoScaleMode =

    System.Windows.Forms.AutoScaleMode.Font;

    this.ClientSize = new System.Drawing.Size(292, 266);

    this.Controls.Add(this.textBox1);

    this.Controls.Add(this.button1);

    this.Name = "Form1";

    this.Text = "Form1";

    this.ResumeLayout(false);

    this.PerformLayout(); // Заставляет элемент

    // управления выполнить для всех дочерних

    // элементов компановку в соответствии

    // с их свойствами

    }

    #endregion

    // Объявление переменных

    private System.Windows.Forms.Button button1;

    private System.Windows.Forms.TextBox textBox1;

    }

    }

    с новым окном подменю MenuStrip

    // Создание объекта MenuStrip с новым окном подменю MenuStrip ms = new MenuStrip(); // Создание подменю ToolStripMenuItem windowMenu = new ToolStripMenuItem("Window"); ToolStripMenuItem windowNewMenu = new ToolStripMenuItem("New", null, // Обработчик данной команды: new EventHandler(windowNewMenu_Click)); // Список элементов меню windowMenu.DropDownItems.Add(windowNewMenu); ((ToolStripDropDownMenu) (windowMenu.DropDown)).ShowImageMargin = false; ((ToolStripDropDownMenu) (windowMenu.DropDown)).ShowCheckMargin = true;

    // Указывает, что ToolStripMenuItem будет отображать // список дочерних форм ms.MdiWindowListItem = windowMenu;

    // Добавление окна ToolStripMenuItem к линейке меню ms.Items.Add(windowMenu);

    // Встраивание линейки меню в верх формы. ms.Dock = DockStyle.Top;

    // Свойство Form.MainMenuStrip определяет линейку меню this.MainMenuStrip = ms;
    Листинг 23.3.
    Закрыть окно





    // Создание объекта MenuStrip с новым окном подменю

    MenuStrip ms = new MenuStrip();

    // Создание подменю

    ToolStripMenuItem windowMenu =

    new ToolStripMenuItem("Window");

    ToolStripMenuItem windowNewMenu =

    new ToolStripMenuItem("New",

    null,

    // Обработчик данной команды:

    new EventHandler(windowNewMenu_Click));

    // Список элементов меню

    windowMenu.DropDownItems.Add(windowNewMenu);

    ((ToolStripDropDownMenu)

    (windowMenu.DropDown)).ShowImageMargin = false;

    ((ToolStripDropDownMenu)

    (windowMenu.DropDown)).ShowCheckMargin = true;

    // Указывает, что ToolStripMenuItem будет отображать

    // список дочерних форм

    ms.MdiWindowListItem = windowMenu;

    // Добавление окна ToolStripMenuItem к линейке меню

    ms.Items.Add(windowMenu);

    // Встраивание линейки меню в верх формы.

    ms.Dock = DockStyle.Top;

    // Свойство Form.MainMenuStrip определяет линейку меню

    this.MainMenuStrip = ms;

    Класс Form

    Класс Systems.Windows.Forms.Form используется для создания окна формы.
    Формы позволяют отображать различные типы окон.
  • SDI-формы - формы, функционирующие как самостоятельное окно.
  • MDI-формы - формы, которые могут содержать дочерние формы (свойство родительского окна IsMdiContainer должно быть равно True. Например: this.IsMdiContainer = true;; свойство дочернего окна MdiParent должно указывать на родительское окно);
  • формы - диалоги - формы, используемые для размещения элементов управления.

  • Для создания MDI-приложения можно в пустой проект добавить новый элемент MDI Parent.
    Для создания формы, идентичной существующей, в проект следует добавить элемент Inherited Form и указать класс копируемой формы.

    Применение стандартных диалогов

    Для открытия и закрытия файла, для выбора рисунка или пиктограммы, для определения цвета библиотека .NET Framework предоставляет набор классов стандартных диалогов.
    Для использования стандартного диалога сначала требуется создать переменную типа данного диалога, а затем вызвать метод ShowDialog. Если в стандартном диалоге было выбрано значение (имя файла, цвет), то метод ShowDialog возвращает значение true.
    Например:
    // Вызов стандартного диалога Open OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.InitialDirectory = Environment.GetFolderPath( Environment.SpecialFolder.Personal); openFileDialog.Filter = "Text Files (*.txt)|*.txt| All Files (*.*)|*.*"; // Стандартные диалоги отображаются методом ShowDialog if (openFileDialog.ShowDialog(this) == DialogResult.OK) // Свойство FileName содержит имя выбранного файла {string FileName = openFileDialog.FileName; }
    // Вызов стандартного диалога SaveAs SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.InitialDirectory = Environment.GetFolderPath( Environment.SpecialFolder.Personal); saveFileDialog.Filter = "Text Files (*.txt)|*.txt| All Files (*.*)|*.*"; if (saveFileDialog.ShowDialog(this) == DialogResult.OK) {string FileName = saveFileDialog.FileName;}

    Работа с меню

    Элемент управления MenuStrip (линейка меню) представляет собой контейнер для меню, размещаемый в форме. Объект ToolStripMenuItem может быть добавлен в MenuStrip. Объект ToolStripMenuItemthat является отдельным элементом меню, который может быть самостоятельной командой или родительским меню для других элементов подменю.
    MenuStrip служит контейнером для объектов следующих классов:
  • ToolStripMenuItem,
  • ToolStripComboBox,
  • ToolStripSeparator,
  • ToolStripTextBox.

  • Класс MenuStrip заменяет и расширяет класс MainMenu предыдущих версий (класс Main-Menu оставлен для обратной совместимости и дальнейшего использования).
    Свойство окна формы MainMenuStrip определяет линейку меню для данного окна.
    Например:
    // Создание объекта MenuStrip с новым окном подменю MenuStrip ms = new MenuStrip(); // Создание подменю ToolStripMenuItem windowMenu = new ToolStripMenuItem("Window"); ToolStripMenuItem windowNewMenu = new ToolStripMenuItem("New", null, // Обработчик данной команды: new EventHandler(windowNewMenu_Click)); // Список элементов меню windowMenu.DropDownItems.Add(windowNewMenu); ((ToolStripDropDownMenu) (windowMenu.DropDown)).ShowImageMargin = false; ((ToolStripDropDownMenu) (windowMenu.DropDown)).ShowCheckMargin = true;
    // Указывает, что ToolStripMenuItem будет отображать // список дочерних форм ms.MdiWindowListItem = windowMenu;
    // Добавление окна ToolStripMenuItem к линейке меню ms.Items.Add(windowMenu);
    // Встраивание линейки меню в верх формы. ms.Dock = DockStyle.Top;
    // Свойство Form.MainMenuStrip определяет линейку меню this.MainMenuStrip = ms;
    Листинг 23.3.
    Для добавления к форме линейки меню следует на панели инструментов выбрать элемент управления MenuStrip (или MainMenu в предыдущих версиях). Работа с меню

    Редактор формы

    Редактор формы позволяет в графическом режиме разместить на форме все требуемые элементы управления, определить первоначальное значение свойств этих элементов и создать для них обработчики событий.
    При размещении в форме нового элемента управления соответствующий код добавляется в файл формы. Аналогично для задания значения каждого свойства в файл формы добавляется соответствующий set-метод. Методы-обработчики событий также помещаются в файл формы.
    Следующий код представляет файл формы для формы, в которую добавлено два элемента управления - поле ввода и командная кнопка:
    namespace D1 { // Подключение используемых пространств имен using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Windows::Forms; using namespace System::Data; using namespace System::Drawing; // ref class объявляет управляемый класс C++ public ref class Form1 : public System::Windows::Forms::Form { public: Form1(void){InitializeComponent();} protected: ~Form1(){if (components) {delete components;}} // Объявление элемента управления "кнопка": private: System::Windows::Forms::Button^ button1; // Объявление элемента управления // "поле ввода": private: System::Windows::Forms::TextBox^ textBox1; // Объявление контейнера private:System::ComponentModel::Container ^components;
    #pragma region Windows Form Designer generated code // Формируется дизайнером формы void InitializeComponent(void) { // Создание объекта "кнопка": this->button1 = (gcnew System::Windows::Forms::Button()); // Создание объекта "поле ввода": this->textBox1 = (gcnew System::Windows::Forms::TextBox()); this->SuspendLayout(); // Временно // приостанавливает события компоновки до // вызова метода ResumeLayout или // Задание свойств для кнопки button1 this->button1->Location = System::Drawing::Point(427, 22); this->button1->Name = L"button1"; this->button1->Size = System::Drawing::Size(75, 23); this->button1->TabIndex = 0; this->button1->Text = L"button1"; this->button1->UseVisualStyleBackColor = true; // Определение обаботчика события Click для кнопки this->button1->Click += gcnew System::EventHandler( this, &Form1::button1_Click); // Задание свойств для поля ввода textBox1 this->textBox1->Location = System::Drawing::Point(80, 25); this->textBox1->Name = L"textBox1"; this->textBox1->Size = System::Drawing::Size(100, 20); this->textBox1->TabIndex = 1; // Задание свойств для формы Form1 this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(548, 266); ..// Добавление в форму элементов управления this->Controls->Add(this->textBox1); this->Controls->Add(this->button1); this->Name = L"Form1"; this->Text = L"Form1"; this->ResumeLayout(false); this->PerformLayout(); } #pragma endregion // Обработчик события для кнопки private: System::Void button1_Click( System::Object^ sender, System::EventArgs^ e) {this->textBox1->Text = L"123456"; } }; // Конец реализации класса } // Конец пространства имен D1

    Листинг 23.1.

    При создании проекта приложения для языка C# сразу создается диалоговая форма. Автоматически формируемое приложение включает в себя файлы, приведенные на рис. 23.1.

    Редактор формы
    Рис. 23.1.  Файлы проекта для C#

    Файл Program.cs - это главный файл приложения, содержащий метод main. В этот файл по умолчанию вставляется следующий код:

    using System; using System.Collections.Generic; using System.Windows.Forms;

    namespace D_1 { static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); // Разрешает использовать для элементов управления визуальные стили. Метод должен быть вызван до добавления в форму элементов управления // Метод введен для .NET Framework version 2.0.: Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); // Создание формы } } }

    Файл Forms.Designer.cs содержит код метода InitializeComponent, в котором к окну формы добавляются все элементы управления и происходит настройка их свойств.

    Также в данный файл помещается код объявления элементов управления, размещаемых в форме:

    namespace D_1 {partial class Form1 { private System.ComponentModel.IContainer components = null; /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); }

    #region Windows Form Designer generated code

    /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.button1 = new System.Windows.Forms.Button(); this.textBox1 = new System.Windows.Forms.TextBox(); this.SuspendLayout(); // Элемент управления button1 this.button1.Location = new System.Drawing.Point(188,27); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(75, 23); this.button1.TabIndex = 0; this.button1.Text = "button1"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // Элемент управления textBox1 this.textBox1.Location = new System.Drawing.Point(42, 30); this.textBox1.Name = "textBox1"; this.textBox1.Size = new System.Drawing.Size(100, 20); this.textBox1.TabIndex = 1; // Окно формы Form1 this.AutoScaleDimensions = // Определяет размер // окна как ширина и высота (тип float) new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(292, 266); this.Controls.Add(this.textBox1); this.Controls.Add(this.button1); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); this.PerformLayout(); // Заставляет элемент // управления выполнить для всех дочерних // элементов компановку в соответствии // с их свойствами } #endregion // Объявление переменных private System.Windows.Forms.Button button1; private System.Windows.Forms.TextBox textBox1; } }

    Листинг 23.2.

    Файл Forms.cs содержит описание всех добавляемых пользователем методов обработки событий ( переход между окном кода и окном дизайнера для формы может быть выполнен вызовом команды контекстного меню View Code или View Designer).

    Для окна формы с двумя элементами управления - командная кнопка и поле ввода, и методом обработки события Click файл Forms.cs может содержать следующий код:

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace D_1 { public partial class Form1 : Form { public Form1() // Конструктор { InitializeComponent(); // Метод определен //в файле Forms.Designer.cs } private void button1_Click(object sender,EventArgs e) { this.textBox1.Text = "123456789"; } } }

    Создание формы

    Формы Windows реализуются набором классов из пространства имен Systems.Windows.Forms.
    Базовым классом для всех окон является класс Form.
    Для создания приложения-диалога на языке С++ следует:
  • В окне дизайнера создать диалоговую форму. Код, соответствующий создаваемой форме, записывается в файл с расширением .h (например, Form1.h).
  • В методе main файла приложения выполнить создание формы вызовом метода Run объекта Application.

  • // D1.cpp : главный файл проекта. #include "stdafx.h" #include "Form1.h" // Файл формы using namespace D1; [STAThreadAttribute] int main(array ^args) { // создание окна формы Application::Run(gcnew Form1()); return 0; }
    Оператор gcnew создает экземпляр управляемого типа. Результатом выполнения данной операции является дескриптор, указывающий на объект управляемого типа. Для объявления переменной типа дескриптора используется операция ^. Доступ к свойствам и методам объекта через дескриптор выполняется операцией ->.

    Создание новой формы

    Для создания и отображения новой формы следует вызвать конструктор формы и затем вызвать метод Show. При этом, если создаваемая форма является дочерней, то следует установить значение свойства MdiParent.
    Например:
    // Создание нового экземпляра дочерней формы Form childForm = new Form(); // Делаем форму дочерней // для MDI-формы // до ее отображения childForm.MdiParent = this; childForm.Text = "Window " + childFormNumber++; childForm.Show(); // Отображаем дочернюю форму

    Закрытие формы

    Закрытие формы выполняется вызовом метода Close. Для того, чтобы закрыть все дочерние формы в MDI-приложении, следует использовать свойство MdiChildren, содержащее массив дочерних форм.
    Например:
    private void CloseAllToolStripMenuItem_Click( object sender, EventArgs e) { foreach (Form childForm in MdiChildren) { childForm.Close(); } }
    Класс Form предоставляет большой набор свойств, включая следующие
    AutoScaletrueОкно и элементы управления масштабируются автоматически в зависимости от размера шрифта
    Border.StyleFormBorder. Style.SizableГраница окна позволяет масштабирование окна
    ControlBoxtrueОкно содержит кнопку системного меню и кнопки управления (в верхнем правом углу). Кнопки управления показываются, если свойства MaximizeBox и MinimizeBox установлены в true
    StartPositionВозможны следующие значения: Manual; CenterScreen; WindowsDefaultLocation; WindowsDefaultBounds; CenterParent
    WindowStateСВозможны следующие значения: Normal; Minimized; Maximized
    MainMenuStripУказывает на линейку меню
    IsMdiContainerОпределяет, допускаются ли дочерние окна
    IsMdiChildОпределяет, является ли форма дочерним окном
    MdiChildrenМассив форм, содержащий дочерние формы
    MdiParentСсылка на родительскую MDI-форму
    ControlsКоллекция дочерних элементов управления
    TextЗаголовок окна
    OwnerFormsМассив форм, принадлежащих данной форме
    OwnerВладелец формы

    Класс Form предоставляет большой набор методов, включая следующие:
  • ActiveForm - возвращает активную форму.
  • Activate - активизирует указанную форму.
  • Close - закрывает форму.
  • Show - показывает форму.
  • ShowDialog - показывает форму в виде модального диалога.
  • Hide - прячет форму.

  • Для формы возможны следующие события:
  • Click - щелчок мышью на форме.
  • Closing - закрытие формы.
  • Closedv - форма закрыта.
  • Load - первоначальное отображение формы.
  • Activated - активация формы.
  • Deactivate - деактивация формы.
  • GotFocus - получение фокуса формой.
  • LostFocus - потеря формой фокуса.
  • MdiChildActivate - активировано дочернее окно для MDI-формы.
  • MouseEnter - курсор мыши помещен над формой.
  • MouseLeave - курсор мыши покинул форму.

  • Дочерние окна в MDI-приложении могут быть упорядочены вызовом метода LayoutMdi.
    Например:
    // Упорядочивание по горизонтали this.LayoutMdi( MdiLayout.TileHorizontal ); // Упорядочивание по вертикали this.LayoutMdi( MdiLayout.TileVertical ); // Расположение каскадом this.LayoutMdi( MdiLayout.Cascade );

    Введение в программирование

    Иерархия классов

    Классы библиотеки VCL используют механизм простого наследования: один класс может иметь только одного предка. Корнем иерархии классов является класс TObject. Любой класс VCL-библиотеки наследуется от класса TObject.
    На рис. 24.1 представлена корневая часть дерева иерархии классов VCL-библиотеки.
    Иерархия классов
    Рис. 24.1.  Иерархия классов VCL-библиотеки

    Класс TApplication

    Класс TApplication инкапсулирует объект "Windows-приложение". Посредством этого класса определяется интерфейс между разработчиком и средой Windows.
    В каждом приложении Delphi всегда автоматически создается один объект Application как экземпляр класса приложения. Для большинства приложений этот объект является экземпляром класса TApplication.
    Компонент TApplication не отображается в палитре компонентов и не имеет публикуемых свойств. Для того чтобы иметь возможность перехватывать события для приложения, используя среду разработки IDE, можно добавить в любую форму проекта компонент TApplicationEvents.
    Класс предоставляет большой набор свойств, включая следующие:
  • HelpFile - определяет имя файла справки.
  • Icon - определяет пиктограмму, отображаемую в строке вместе с именем приложения.
  • MainForm - определяет главную форму приложения. Она действует как главное окно приложения. При закрытии этой формы завершается и работа приложения.
  • ShowMainForm - если значение свойства равно True (по умолчанию), то главное окно приложения показывается автоматически при запуске приложения. Чтобы при запуске приложения главное окно приложения было скрыто, следует в главном файле проекта до выполнения метода Application.Run установить значение данного свойства равным False и одновременно для формы, определенной как главное окно приложения, установить значение свойства Visible равным False.
  • Title - определяет заголовок приложения.


  • Класс TComponent

    TComponentявляется предком всех компонентов VCL-библиотеки.
    Все потомки данного класса могут быть расположены в палитре компонентов.
    Класс TComponent позволяет определять родительский элемент управления и владельца компонента.
    Родительским элементом управления называется тот, в который непосредственно помещен данный компонент.
    Владельцем всех компонентов, расположенных в форме, является сама форма.
    Владельцем всех форм является приложение.
    Если компонент расположен не непосредственно в форме, а, например, в компоненте типа TPanel, то владелец и родительский элемент управления у него будут различны.
    Класс предоставляет большой набор свойств, включая следующие:
  • ComObject - определяет ссылку на интерфейс, наследуемый от IUnknown и реализованный компонентом. Используется только для компонентов, поддерживающих СОМ-интерфейс.
  • ComponentCount - указывает количество компонентов, принадлежащих данному компоненту.
  • ComponentIndex - указывает индекс компонента в массиве Components владельца данного компонента. Первый компонент в списке имеет индекс 0.
  • Components - список всех компонентов, принадлежащих данному компоненту. Используется для ссылки на компонент по его индексу или для последовательного доступа ко всем компонентам, принадлежащих данному компоненту.
  • Name - указывает имя компонента, используемое в коде программы для доступа к его свойствам и методам. При создании компонента Delphi автоматически назначает ему имя на основе имени класса компонента.
  • Owner - указывает компонент, владеющий данным компонентом. Компонент всегда удаляется (освобождается память) при удалении его владельца.


  • Класс TControl

    TControl - это базовый класс всех элементов управления (включая и окно формы). Эти компоненты могут быть видимы во время выполнения. Для них определены такие свойства, как позиция, курсор, всплывающая подсказка, методы для рисования или перемещения элемента управления, события для манипуляций с помощью мыши.
    Класс предоставляет большой набор свойств, включая следующие:
  • Action - назначает действие (объект action), ассоциируемый с данным элементом управления.
  • AutoSize - определяет, будет ли элемент управления автоматически изменять свой размер при изменении его содержимого.
  • TCaption - определяет строку, отображаемую как заголовок окна или метку. Символ & в заголовке указывает, что следующий за ним символ будет отображаться подчеркнутым. Такой символ определяет клавишу-акселератор. При одновременном нажатии этой клавиши и клавиши Alt происходит перемещение фокуса ввода на данный элемент управления. Для того, чтобы показать в заголовке сам символ амперсанда, следует ввести два символа &&.
  • Color - позволяет определять или изменять фоновый цвет элемента управления. Если значение свойства ParentColor равно True, то при изменении фона родительского элемента управления происходит и автоматическое изменение фона дочернего элемента управления.
  • Enabled - определяет, доступен ли элемент управления.
  • Font - определяет атрибуты текста, такие, как шрифт, начертание, размер, цвет и т.п.
  • Height и Width - определяют вертикальный и горизонтальный размер элемента управления в пикселях.
  • HelpType - определяет, каким образом для элемента управления будет специфицирована тема файла справки. Если значение свойства равно htContext, то ID справки содержится в свойстве HelpContext. Если значение свойства равно htKeyword, то тему справки определяет свойство HelpKeyword.
  • HelpContext - определяет числовой ID темы справки, отображаемой как контекстно-зависимая справка.
  • HelpKeyword - определяет тему в файле справки.
  • Hint - содержит подсказку, отображаемую при расположении и задержании указателя мыши над элементом управления.
    Подсказка отображается только, если значение свойства ShowHint установлено равным True.
  • Left - определяет горизонтальную координату элемента управления относительно его родительского элемента.
  • Parent - указывает родительский элемент управления.
  • ParentColor и ParentFont - если это свойства равны true, то используются цвет и шрифт родительского элемента управления.
  • PopupMenu - определяет всплывающее меню (контекстное меню), ассоциируемое с данным элементом управления. Если свойство AutoPopup объекта типа TPopupMenu равно True, то меню будет отображаться автоматически. Если это свойство равно False, то для отображения всплывающего меню следует в обработчике события OnContextPopup вызвать метод Popup.
  • ShowHint - определяет, будет ли для элемента управления отображаться окно всплывающей подсказки.
  • Text - содержит строку текста, располагаемую в элементе управления.
  • Visible - определяет, является ли компонент видимым.


  • Класс предоставляет большой набор методов, включая следующие:

  • Click - инициирует событие OnClick.
  • Create - создает экземпляр класса TControl и выполняет инициализацию его свойств.
  • DblClick - инициирует событие OnDblClic.
  • Hide - скрывает элемент управления.
  • Refresh - сразу перерисовывает на экране элемент управления, вызывая метод Repaint.
  • Show - делает элемент управления видимым, одновременно устанавливая значение его свойства Visible равным True.


  • Класс TForm

    TForm является базовым классом для создания окна формы.
    По умолчанию каждая новая создаваемая форма реализуется как потомок класса TForm. Форма может быть:
  • главным окном приложения;
  • диалоговым окном;
  • дочерним окном MDI-окна.

  • Класс предоставляет большой набор свойств, включая следующие:
  • Active - определяет, является ли форма активной.
  • ActiveControl - определяет элемент управления формы, имеющий фокус ввода.
    Например:
    if ActiveControl <> nil then ActiveControl.Left := ActiveControl.Left + 1; end;
  • ActiveMDIChild - определяет активное дочернее окно MDI-приложения;
  • BorderStyle - определяет внешний вид и поведение рамки окна формы;
  • FormStyle - определяет стиль формы, который указывается одним из следующих значений:
  • fsNormal - форма определена как простая SDI-форма и не является ни дочерним, ни родительским MDI-окном;
  • fsMDIChild - форма является дочерним MDI-окном.
  • fsMDIForm - форма является родительским MDI-окном.
  • fsStayOnTop- для формы определено поведение "всегда сверху" (она остается сверху всех других форм проекта, для которых не установлен стиль fsStayOnTop).

  • HelpFile - указывает имя файла, используемого для отображения справки.
  • Icon - определяет пиктограмму, отображаемую в заголовке окна формы.
  • MDIChildCount - определяет количество открытых дочерних MDI-форм.
  • MDIChildren - содержит список всех дочерних MDI-форм.
    Например:
    {Закрытие всех дочерних MDI-форм} var Index1: Integer; begin with MyForm1 do for I := MDIChildCount-1 downto 0 do MDIChildren[Index1].Close; end;
  • Menu - определяет главное меню.
  • Parent - определяет родительское окно. Если форма не имеет родителя, то значение свойства Parent равно nil.
  • Position - указывает размер и позицию, используемые для первоначального отображения формы.
  • WindowState - определяет, в каком виде форма появляется на экране: свернутой, полноэкранной или в нормальном представлении.

  • Класс формы предоставляет большой набор методов, включая следующие:
  • Cascade - упорядочивает все дочерние MDI-формы, располагая их каскадом.
  • Next - делает активной следующую дочернюю форму (в той последовательности, как они были открыты).
  • Previous - делает активной предыдущую дочернюю форму.
  • Tile - упорядочивает все дочерние MDI-формы таким образом, чтобы они все имели одинаковый размер и умещались одновременно в клиентской области родительского окна.

  • Например:
    {Обработчик события для команды меню Windows | Tile} procedure TForm1.TileFormsClick(Sender: TObject); begin this.TileMode := tbVertical; this.Tile; end;
    Класс формы является контейнером для всех компонентов, размещаемых на форме. Для доступа к свойствам формы или именам компонентов можно использовать ключевое слово this. Если перед именем свойства отсутствует какой-либо идентификатор, то по умолчанию предполагается, что это свойство формы.

    Класс TMainMenu

    Класс TMainMenu инкапсулирует поведение линейки меню (menu bar) и соответствующих ниспадающих меню (drop-down menus) для окна формы.
    Этот класс определяет свойства и методы, позволяющие соединять ниспадающие меню главного меню с главными меню других форм и помогающие взаимодействовать с меню для OLE-объектов.
    Процесс создания меню формы очень прост. Он состоит из трех этапов:
  • добавления в форму компонента класса TMainMenu;
  • выполнения на нем двойного щелчка мышью и ввода в открытое далее окно заголовков всех пунктов линейки меню и пунктов ниспадающих меню;
  • определения кода обработчиков событий для каждого пункта меню.

  • Если требуется синхронизировать код, выполняемый для пункта меню, с кодом, выполняемым для кнопки на панели управления, то создается объект "действие типа Taction", который указывается и для пункта меню, и для кнопки.
    Класс предоставляет набор свойств, включая следующие:
  • AutoMerge - определяет возможность слияния меню. Каким образом меню будут объединяться, зависит от значения свойства GroupIndex каждого отдельного пункта меню;
  • Handle - обеспечивает доступ к дескриптору меню. Это свойство используется для функций Windows API, требующих дескриптора меню.


  • Класс TMenuItem

    Класс TMenuItem реализует поведение пунктов меню. Контейнером для объектов типа TMenuItem может быть компонент типа TMainMenu (линейка главного меню) или компонент типа TPopupMenu (контекстное меню).
    При создании меню на этапе проектирования редактор меню Menu Designer автоматически создает объекты типа TMenuItem для каждой команды меню.
    Класс предоставляет набор свойств, включая следующие:
  • Action - определяет объект действие (Action), ассоциируемый с пунктом меню. По умолчанию для каждого пункта меню стандартным событием считается OnClick и обработчиком события является процедура, имя которой автоматически формируется из имени формы и имени объекта "пункт меню", указанных через точку (например, TForm1.item12Click). Объект "действие" позволяет определить одну процедуру обработки события, которую далее можно будет многократно использовать для различных объектов при обработке событий.
  • AutoHotkeys - определяет, будут ли клавиши-акселераторы для элементов подменю устанавливаться автоматически.
  • Bitmap - определяет изображение, отображаемое слева от заголовка меню.
  • Break - определяет, будет ли пункт меню располагаться в новом столбце меню.
  • Caption - определяет текст пункта меню. Если перед буквой в заголовке пункта меню стоит символ &, то данная буква называется клавишей-акселератором, а выбор пункта меню может быть выполнен одновременным нажатием Alt и клавиши-акселератора.
  • Checked - определяет, будет ли маркер переключателя появляться в пункте меню слева от заголовка.
  • Default - определяет, является ли данный пункт меню пунктом, выполняемым по умолчанию при двойном щелчке мышью на родительском подменю. Пункт меню, выполняемый по умолчанию, отмечается полужирным начертанием.
  • Enabled - определяет, доступен ли пункт меню.
  • GroupIndex - указывает логическую группу, к которой принадлежит пункт меню (группы используются для управления слиянием пунктов меню).

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

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

    Если значение свойства GroupIndex добавляемого пункта линейки меню лежит между значениями свойства GroupIndex пунктов линейки меню главного окна, то добавляемый пункт вставляется между ними.

  • HelpContext - указывает ID контекста справки, отображаемой для пункта меню.
  • Hint - определяет текст всплывающего окна подсказки.
  • ImageIndex - определяет индекс изображения, отображаемого для пункта меню. Список изображений, указываемых через индекс, содержится в свойстве Images родительского меню: для пунктов меню верхнего уровня список определяется свойством Images объекта типа TMenu или TPopupMenu, а для пунктов подменю список определяется свойством Images родительского объекта меню типа TMenuItem. Если родительское меню не содержит списка изображений в свойстве Images, то для определения отображаемого изображения будет использовано значение свойства Bitmap пункта меню.
  • Items - список пунктов меню в подменю.
  • MenuIndex - указывает индекс пункта меню в родительском меню.
  • Parent - определяет для пункта меню его родительское меню.
  • Visible - определяет, является ли пункт меню видимым.


  • Класс предоставляет набор методов, включая следующие:

  • Add - добавляют в конец списка Items один или несколько пунктов меню.

    Например:

    var NewItem: TMenuItem; i : integer; begin // Создание элемента "разделительная линия": NewItem := TMenuItem.Create(Self); NewItem.Caption := '-'; // Заголовок пункта меню // Добавление пункта меню к меню Windows: Windows.Add(NewItem); // Cоздадим и добавим пункт меню для каждой формы for i := 0 to Screen.FormCount-1 do begin NewItem := TMenuItem.Create(Self); NewItem.Caption := Screen.Forms[i].Name; Windows.Add(NewItem); end; end;
  • Clear - удаляет все пункты меню, указанные в списке свойства Items.
  • Click - инициирует событие OnClick.


    Этот метод может быть переопределен разработчиком для того, чтобы запрограммировать собственный ответ на выбор пользователем пункта меню.
  • Create - создает новый пункт меню.
  • Delete - удаляет из списка свойства Items пункт меню с указанным индексом.
  • IndexOf - возвращает позицию указанного пункта меню в списке Items.
  • Insert - вставляет указанный пункт меню в заданную позицию списка Items.


  • Разработчик может создать один общий объект "действие" и для пункта меню, и для кнопки панели инструментов. Для определения действия на этапе проектирования следует:

  • добавить в форму объект типа TactionList;
  • вызвать редактор объекта "действие", выполнив на нем двойной щелчок мышью;
  • добавить в открывшемся редакторе объекты "действие (типа TAction)";
  • по двойному щелчку на имени любого объекта "действие" отображается редактор кода с автоматически добавленным обработчиком события для данного действия. Например: procedure TForm1.Action1Execute(Sender: TObject); begin end; Внутри блока begin end следует ввести код обработчика события;
  • в завершение нужно определить для объекта "пункт меню" значение свойства Action, выбрав его из списка действий объекта типа TActionList.


  • Класс TObject

    Класс TObject инкапсулирует общие черты поведения всех объектов VCL-библиотеки. Если при создании нового объекта не указан базовый класс, то Delphi автоматически использует как предка класс TObject.
    Объявление нового класса выполняется в секции type. Если после слова class в скобках не указано никакого наследуемого класса, то по умолчанию предполагается, что создаваемый класс наследуем от класса TObject.
    Например:
    type TMyClass = class // Эти два объявления type TMyClass = class(TObject) //являются эквивалентными

    Класс TPopupMenu

    Класс TPopupMenu инкапсулирует поведение контекстных меню, также называемых всплывающими или popup-меню.
    Он предназначен для создания меню, отображаемых при щелчке пользователя правой кнопкой мыши на элементе управления. Чтобы контекстное меню поставить в соответствие конкретному элементу управления, следует установить значение свойства PopupMenu элемента управления равным имени объекта TPopupMenu. Для этого в инспекторе объектов следует выбрать значение свойства PopupMenu из автоматически предлагаемого списка объектов типа TPopupMenu.
    Базовым классом для TPopupMenu является класс TMenu.
    Следующий пример иллюстрирует отображение контекстного меню в указанной точке экрана по щелчку мыши:
    procedure Form1.FormCreate(Sender: TObject); begin PopupMenu1.AutoPopup := False; end; procedure Form1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin PopupMenu1.Popup(X, Y); end;
    Класс TPopupMenu

    Класс TScreen

    Каждое приложение Delphi имеет глобальную переменную Screen типа TScreen. Эта переменная определена как var Screen: TScreen;.
    Компонент TScreen, так же как и компонент TApplication, недоступен из инспектора объектов. Этот компонент предназначен для обеспечения доступа к устройству вывода - экрану. Его свойства содержат информацию об используемом разрешении монитора, курсорах и шрифтах, доступных для приложения, списке форм приложения и активной форме.

    Класс TWinControl

    Класс TWinControl является базовым классом всех оконных элементов управления.
    Класс предоставляет большой набор свойств, включая следующие:
  • ControlCount - указывает количество дочерних элементов управления.
  • Controls - содержит список всех дочерних элементов управления.
  • TabOrder - указывает номер элемента управления в табулированном порядке родительского элемента управления.


  • Компоненты

    Компонент Delphi - это особый вид объектов - визуальный объект (визуальный для проектирования, а не для отображения пользователя). Создавать и редактировать такой объект можно как программным путем, так и на этапе проектирования.
    При выполнении программы компоненты делятся на визуальные, которые видит пользователь, и невизуальные, для которых нет возможности их отображения, но доступ к свойствам которых разрешен.
    Все компоненты имеют общего предка - класс TComponent .
    Delphi предоставляет широкий набор компонентов, называемый иногда VCL-библиотекой. Все компоненты Delphi могут быть доступны через палитру компонентов.
    В настоящее время в Borland Developer Studio входит Delphi 2006 for Win32 (использует библиотеку VCL) и Delphi 2006 for Microsoft .NET (использует библиотеку Framework 1.1).
    Часть компонентов являются элементами управления. В основном это элементы управления Windows. Доступ к элементам управления возможен не только на этапе проектирования, но и во время выполнения приложения.
    Элементы управления можно подразделить на оконные и неоконные. Оконные элементы могут получать фокус и имеют дескриптор окна. Предком всех оконных элементов управления является абстрактный класс TWinControl. Предком неоконных элементов управления является абстрактный класс TGraphicControl.
    При добавлении в форму любого компонента из палитры компонентов Delphi автоматически формирует программный код для создания объекта (переменной) данного типа. Переменная добавляется как член класса данной формы.

    Объекты

    Объект Delphi представляет собой набор свойств и методов, включающих также обработчики событий. Свойства, называемые иногда атрибутами, являются данными, содержащимися в объекте. Методы описывают действия, реализованные для данного объекта.
    Все объекты имеют общего предка - класс TObject.

    Введение в программирование

    Компонент главного меню} File1: TMenuItem;

    type TMainForm = class(TForm) MainMenu1: TMainMenu; { Компонент главного меню} File1: TMenuItem; {Компоненты элементов меню} FileNewItem: TMenuItem; FileOpenItem: TMenuItem; FileCloseItem: TMenuItem; Window1: TMenuItem; Help1: TMenuItem; N1: TMenuItem; FileExitItem: TMenuItem; WindowCascadeItem: TMenuItem; WindowTileItem: TMenuItem; WindowArrangeItem: TMenuItem; HelpAboutItem: TMenuItem; OpenDialog: TOpenDialog; FileSaveItem: TMenuItem; FileSaveAsItem: TMenuItem; Edit1: TMenuItem; CutItem: TMenuItem; CopyItem: TMenuItem; PasteItem: TMenuItem; WindowMinimizeItem: TMenuItem; StatusBar: TStatusBar; {Компонент строки состояния} ActionList1: TActionList; {Компонент для определения списка именованных действий} EditCut1: TEditCut; {Компонент для копирования в буфер обмена} EditCopy1: TEditCopy; EditPaste1: TEditPaste; FileNew1: TAction; {Компонент именованного действия} FileSave1: TAction; FileExit1: TAction; FileOpen1: TAction; FileSaveAs1: TAction; WindowCascade1: TWindowCascade; WindowTileHorizontal1: TWindowTileHorizontal; WindowArrangeAll1: TWindowArrange; WindowMinimizeAll1: TWindowMinimizeAll; HelpAbout1: TAction; FileClose1: TWindowClose; WindowTileVertical1: TWindowTileVertical; WindowTileItem2: TMenuItem; ToolBar2: TToolBar; {Панель инструментов} ToolButton1: TToolButton; {Кнопки панели инструментов} ToolButton2: TToolButton; ToolButton3: TToolButton; ToolButton4: TToolButton; ToolButton5: TToolButton; ToolButton6: TToolButton; ToolButton9: TToolButton; ToolButton7: TToolButton; ToolButton8: TToolButton; ToolButton10: TToolButton; ToolButton11: TToolButton; ImageList1: TImageList; procedure FileNew1Execute(Sender: TObject); procedure FileOpen1Execute(Sender: TObject); procedure HelpAbout1Execute(Sender: TObject); procedure FileExit1Execute(Sender: TObject); end;

    Листинг 25.1.
    Закрыть окно





    type

    TMainForm = class(TForm)

    MainMenu1: TMainMenu; {Компонент главного меню}

    File1: TMenuItem; {Компоненты элементов меню}

    FileNewItem: TMenuItem;

    FileOpenItem: TMenuItem;

    FileCloseItem: TMenuItem;

    Window1: TMenuItem;

    Help1: TMenuItem;

    N1: TMenuItem;

    FileExitItem: TMenuItem;

    WindowCascadeItem: TMenuItem;

    WindowTileItem: TMenuItem;

    WindowArrangeItem: TMenuItem;

    HelpAboutItem: TMenuItem;

    OpenDialog: TOpenDialog;

    FileSaveItem: TMenuItem;

    FileSaveAsItem: TMenuItem;

    Edit1: TMenuItem;

    CutItem: TMenuItem;

    CopyItem: TMenuItem;

    PasteItem: TMenuItem;

    WindowMinimizeItem: TMenuItem;

    StatusBar: TStatusBar; {Компонент строки состояния}

    ActionList1: TActionList; { Компонент для определения

    списка именованных действий}

    EditCut1: TEditCut; {Компонент для копирования

    в буфер обмена}

    EditCopy1: TEditCopy;

    EditPaste1: TEditPaste;

    FileNew1: TAction; {Компонент именованного действия}

    FileSave1: TAction; FileExit1: TAction;

    FileOpen1: TAction; FileSaveAs1: TAction;

    WindowCascade1: TWindowCascade;

    WindowTileHorizontal1: TWindowTileHorizontal;

    WindowArrangeAll1: TWindowArrange;

    WindowMinimizeAll1: TWindowMinimizeAll;

    HelpAbout1: TAction;

    FileClose1: TWindowClose;

    WindowTileVertical1: TWindowTileVertical;

    WindowTileItem2: TMenuItem;

    ToolBar2: TToolBar; {Панель инструментов}

    ToolButton1: TToolButton; {Кнопки панели инструментов}

    ToolButton2: TToolButton;

    ToolButton3: TToolButton;

    ToolButton4: TToolButton;

    ToolButton5: TToolButton;

    ToolButton6: TToolButton;

    ToolButton9: TToolButton;

    ToolButton7: TToolButton;

    ToolButton8: TToolButton;

    ToolButton10: TToolButton;

    ToolButton11: TToolButton;

    ImageList1: TImageList;

    procedure FileNew1Execute(Sender: TObject);

    procedure FileOpen1Execute(Sender: TObject);

    procedure HelpAbout1Execute(Sender: TObject);

    procedure FileExit1Execute(Sender: TObject);

    end;

    Заголовком окна будет имя файла}

    {Создать новый документ} procedure TMainForm.FileNew1Execute(Sender: TObject); begin {Создание дочернего окна с новым именем} CreateMDIChild('NONAME' + IntToStr(MDIChildCount + 1)); end; {Открыть документ} procedure TMainForm.FileOpen1Execute(Sender: TObject); begin if OpenDialog.Execute then {Выбор имени документа} CreateMDIChild(OpenDialog.FileName); {Создание окна} end; procedure TMainForm.CreateMDIChild(const Name: string); var Child: TMDIChild; begin { Класс TMDIChild определен в модуле CHILDWIN.PAS } Child := TMDIChild.Create(Application); {Создание окна} Child.Caption := Name; { Заголовком окна будет имя файла} if FileExists(Name) then // Дочернее окно содержит поле типа TMemo, в которое // выполняется загрузка текстового файла: Child.Memo1.Lines.LoadFromFile(Name); end; Для завершения приложения выполняется следующая процедура: procedure TMainForm.FileExit1Execute(Sender: TObject); begin Close; end; В модуле childwin.pas находится код дочерней формы: type TMDIChild = class(TForm) Memo1: TMemo; {Поле для отображения текста} procedure FormClose(Sender: TObject; var Action: TCloseAction); end; implementation procedure TMDIChild.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; end.

    Листинг 25.2.
    Закрыть окно





    {Создать новый документ}

    procedure TMainForm.FileNew1Execute(Sender: TObject);

    begin

    {Создание дочернего окна с новым именем}

    CreateMDIChild('NONAME' + IntToStr(MDIChildCount + 1));

    end;

    {Открыть документ}

    procedure TMainForm.FileOpen1Execute(Sender: TObject);

    begin

    if OpenDialog.Execute then {Выбор имени документа}

    CreateMDIChild(OpenDialog.FileName); {Создание окна}

    end;

    procedure TMainForm.CreateMDIChild(const Name: string);

    var

    Child: TMDIChild;

    begin

    { Класс TMDIChild определен в модуле CHILDWIN.PAS }

    Child := TMDIChild.Create(Application); {Создание окна}

    Child.Caption := Name; {Заголовком окна будет

    имя файла}

    if FileExists(Name) then

    // Дочернее окно содержит поле типа TMemo, в которое

    // выполняется загрузка текстового файла:

    Child.Memo1.Lines.LoadFromFile(Name);

    end;

    Для завершения приложения выполняется следующая процедура:

    procedure TMainForm.FileExit1Execute(Sender: TObject);

    begin Close; end;

    В модуле childwin.pas находится код дочерней формы:

    type

    TMDIChild = class(TForm)

    Memo1: TMemo; {Поле для отображения текста}

    procedure FormClose(Sender: TObject;

    var Action: TCloseAction);

    end;

    implementation

    procedure TMDIChild.FormClose(Sender: TObject;

    var Action: TCloseAction);

    begin Action := caFree; end;

    end.

    Window1 object StatusBar: TStatusBar AutoHint

    object MainForm: TMainForm Caption = 'Приложение с MDI-интерфейсом' FormStyle = fsMDIForm Menu = MainMenu1 WindowMenu = Window1 object StatusBar: TStatusBar AutoHint = True Panels = <> SimplePanel = True end object ToolBar2: TToolBar Images = ImageList1 object ToolButton9: TToolButton Action = FileNew1 {Именованное действие, которое будет выполнено при щелчке на кнопке} end object ToolButton1: TToolButton Action = FileOpen1 end {Кнопки панели инструментов} ... end object MainMenu1: TMainMenu Images = ImageList1 object File1: TMenuItem Caption = '&File' object FileNewItem: TMenuItem Action = FileNew1 end object FileOpenItem: TMenuItem Action = FileOpen1 end object FileCloseItem: TMenuItem Action = FileClose1 end ... object FileExitItem: TMenuItem Action = FileExit1 end end object Edit1: TMenuItem ... end object Window1: TMenuItem ... end end object OpenDialog: TOpenDialog {Диалог Open} Filter = 'All files (*.*)|*.*' end object ActionList1: TActionList object FileNew1: TAction Category = 'File' Caption = '& New' OnExecute = FileNew1Execute end object FileOpen1: TAction Category = 'File' Caption = '&Open' OnExecute = FileOpen1Execute end ... end end

    Листинг 25.3.
    Закрыть окно





    object MainForm: TMainForm

    Caption = 'Приложение с MDI-интерфейсом'

    FormStyle = fsMDIForm

    Menu = MainMenu1

    WindowMenu = Window1

    object StatusBar: TStatusBar

    AutoHint = True

    Panels = <>

    SimplePanel = True

    end

    object ToolBar2: TToolBar

    Images = ImageList1

    object ToolButton9: TToolButton

    Action = FileNew1 {Именованное действие,

    которое будет выполнено при щелчке на кнопке}

    end

    object ToolButton1: TToolButton

    Action = FileOpen1

    end

    {Кнопки панели инструментов}

    ...

    end

    object MainMenu1: TMainMenu

    Images = ImageList1

    object File1: TMenuItem

    Caption = '&File'

    object FileNewItem: TMenuItem

    Action = FileNew1

    end

    object FileOpenItem: TMenuItem

    Action = FileOpen1

    end

    object FileCloseItem: TMenuItem

    Action = FileClose1

    end

    ...

    object FileExitItem: TMenuItem

    Action = FileExit1

    end

    end

    object Edit1: TMenuItem

    ...

    end

    object Window1: TMenuItem

    ...

    end

    end

    object OpenDialog: TOpenDialog {Диалог Open}

    Filter = 'All files (*.*)|*.*'

    end

    object ActionList1: TActionList

    object FileNew1: TAction

    Category = 'File'

    Caption = '&

    New'

    OnExecute = FileNew1Execute

    end

    object FileOpen1: TAction

    Category = 'File'

    Caption = '&Open'

    OnExecute = FileOpen1Execute

    end

    ...

    end

    end

    Главная форма приложения

    По умолчанию при добавлении в проект новой формы для нее в главном файле приложения автоматически формируется строка кода для создания формы.
    Например:
    Application.CreateForm (TForm1, Form1);.
    Для добавления в проект новой формы достаточно выполнить команду меню File|New Form.
    Окно свойств проекта позволяет определить:
  • главную форму приложения - файл, выполняемый первым;
  • список автоматически создаваемых форм;
  • список доступных форм - чтобы их использовать, их надо будет создать.

  • Если приложение содержит много форм, то для автоматического создания всех форм может не хватить памяти. Более рационально создавать формы по мере необходимости.
    Для создания формы используется метод Create.
    Созданная форма может быть отображена:
  • как обычный диалог - вызовом метода Show;
  • как модальный диалог - вызовом метода ShowModal.


  • Использование модальной формы

    Выполнение модальной формы завершается сразу после вызова метода ShowModal, поэтому память из под нее следует освобождать в вызывающей форме вызовом метода Free.
    Например:
    Form2:=TForm2.Create(self) ; Form2.ShowModal; Form2.Free;
    Результат выполнения модальной формы устанавливается свойством ModalResult командных кнопок. Для того чтобы проверить код ответа (какая кнопка была нажата), следует сравнить значение, возвращаемое методом ShowModal.
    Например:
    if Form2.ShowModal = mrOk then // Нажата кнопка Ок else Abort; // Завершение приложения
    Для закрытия модального диалога не следует вызывать метод Close, достаточно использовать командные кнопки с установленным значением свойства ModalResult.

    Использование немодальной формы

    Время жизни обычного немодального диалога неопределенно и не завершается после вызова метода Show. Поэтому обычный диалог следует завершать в обработчике события OnClose.
    Для вызова этого обработчика события можно вызвать метод Close или выполнить щелчок мышью по соответствующей кнопке в строке заголовка окна.
    Если перед запуском диалога он был создан (не является автоматически создаваемым), то после его закрытия следует освободить занимаемую им память. Это выполняется в обработчике события OnClose вызовом метода Release.

    Классы стандартных диалогов

    Страница Dialogs палитры компонентов содержит ряд компонентов, предназначенных для реализации различных стандартных диалогов. Это диалоги для открытия файла, сохранения файла, выбора цвета или шрифта, открытия или сохранения графического файла.
    Стандартный диалог открывается при вызове метода Execute. При выборе пользователем значения или щелчке пользователя на кнопке OK возвращается значение True. Если пользователь нажал кнопку Cancel или клавишу Escape, то выполнение стандартного диалога возвращает значение False. Для настройки появления и поведения диалога используется свойство Options. Чтобы закрыть диалог программно, следует вызвать метод CloseDialog.
    В следующей таблице приведено описание стандартных диалогов, доступных посредством страницы Dialogs палитры компонентов.
    КлассОписание действия
    TOpenDialogОтображает стандартный диалог Open(имя выбранного файла указываетсяв свойстве FileName)
    TSaveDialogОтображает стандартный диалог Save
    TOpenPictureDialogОтображает стандартный модальный диалог для выбора и открытия графических файлов. Этот диалог идентичен диалогу Open, но имеет дополнительно панель для просмотра изображения
    TSavePictureDialogОтображает стандартный диалог для сохранения графических файлов. Этот диалог имеет панель для просмотра изображения
    TFontDialogВыводит стандартный диалог Font, используемый для определения шрифта, размера и стиля отображения данных
    СTColorDialogОтображает стандартный диалог Color (выбранный цвет указывается в свойстве Color)
    TPrintDialogОтображает стандартный диалог Print
    TPrinterSetupDialogОтображает стандартный диалог Printer Setup
    TFindDialogОтображает стандартный диалог Find
    TReplaceDialogОтображает стандартный диалог Replace

    Следующий пример иллюстрирует использование стандартного диалога для выбора имени открываемого файла:
    var F: TextFile; S: string; begin if OpenDialog1.Execute then // Показать диалог Open begin AssignFile(F, OpenDialog1.FileName); // Назначить // файловой переменной имя выбранного файла Reset(F); Readln(F, S); //Прочитать первую строку файла Edit1.Text := S; // Поместить строку в компонент TEdit CloseFile(F); // Закрыть файл end; end;
    Классы стандартных диалогов

    Проекты

    Любое приложение в среде проектирования Delphi создается как некоторый проект. В зависимости от типа приложения, в проект входит различный набор файлов проекта. Но в любом случае составной частью проекта является файл проекта с расширением DPR. Каждая форма в проекте представляется двумя файлами: файл модуля с расширением PAS и файл описания формы с расширением DFM. Файл описания формы не может редактироваться непосредственно, данные в него заносятся средой проектирования. В каждый проект входит один главный файл приложения. Для диалоговых приложений этот файл начинается с ключевого слова program. Файл модуля для формы начинается ключевым словом unit.
    Для создания нового приложения среда проектирования Delphi предоставляет большой набор шаблонов приложений, включающий приложение-диалог, SDI-приложение и MDI-приложение.
    Основное отличие автоматически формируемого макета приложения на базе шаблона MDI-приложения от применения шаблона SDI-приложения заключается в поддержке одновременной работы с несколькими документами. Каждый новый документ открывается в создаваемом дочернем окне.
    Дополнительно шаблон MDI-приложения содержит кнопки для изменения расположения окон, а в меню Windows добавляются имена всех открытых документов.

    Создание DLL-библиотеки

    DLL-библиотека позволяет объединить в единое целое повторно используемый код. Функции из DLL-библиотеки могут подключаться динамически во время выполнения, в отличие от функций из пакетов Delphi линкуемых статически на этапе компиляции приложения.
    Для того чтобы создать DLL-библиотеку, следует использовать шаблон приложения DLL Wizard.
    В отличие от обычного модуля, начинающегося с ключевого слова unit, модуль DLL-библиотеки начинается с ключевого слова library.
    Секция uses модуля DLL-библиотеки требует подключения только двух пакетов: SysUtils и Classes.
    Функции из DLL-библиотеки могут вызываться как из приложений, разработанных в Delphi, так и из приложений, написанных на других языках программирования, таких как C++.
    Порядок выделения памяти под параметры и освобождения ее различен для разных языков программирования. Чтобы не возникла ошибка времени выполнения, объявление функции в DLL-библиотеке и ее объявление в приложении должны использовать одинаковый механизм передачи параметров.
    При объявлении процедуры или функции может быть указан один из следующих механизмов передачи параметров:
  • register
  • cdecl,
  • stdcall,
  • safecall.

  • Способ передачи параметров указывается через точку с запятой после описания функции.
    Например: function F1(X, Y, Z: Real): Real; stdcall;
    Различные способы передачи параметров определяют порядок их передачи (слева направо или справа налево), а также указывают, кто будет освобождать память стека (вызываемая или вызывающая процедура).
    Для того чтобы функцию, описанную в DLL-библиотеке, можно было вызвать из другого приложения, эту функцию следует экспортировать. Список всех экспортируемых функций указывается в секции exports через запятую и завершается символом "точка с запятой".
    Экспорт функций может выполняться тремя способами:
  • по имени функции, используемому в DLL-библиотеке;
  • по имени функции, заданному как имя экспорта;
  • по присвоенному функции индексу (указанному в секции exports).

  • Например:
    library Project1; uses SysUtils, Classes; {$R *.res} function F1(X: Integer): Integer; stdcall; begin F1:=X*2; end; function F2(X: Integer): Integer; stdcall; begin F2:=X*X; end; exports F1 , {Функция будут доступна по имени F1} F2 index 2 ; {Функция будут доступна по индексу 2} end.
    DLL-библиотека не является выполняемым модулем, поэтому для получения dll-файла достаточно произвести компиляцию проекта.

    Создание MDI-приложения

    При использовании шаблона MDI-приложения создается проект, состоящий из трех модулей (main.pas, childwin.pas, about.pas) и главного файла приложения.
    Для главной формы приложения (main.pas) свойство FormStyle будет установлено равным fsMDIForm, а для дочерней формы (childwin.pas) - fsMDIChild.
    Класс главной формы приложения определяется следующим кодом:
    type TMainForm = class(TForm) MainMenu1: TMainMenu; {Компонент главного меню} File1: TMenuItem; {Компоненты элементов меню} FileNewItem: TMenuItem; FileOpenItem: TMenuItem; FileCloseItem: TMenuItem; Window1: TMenuItem; Help1: TMenuItem; N1: TMenuItem; FileExitItem: TMenuItem; WindowCascadeItem: TMenuItem; WindowTileItem: TMenuItem; WindowArrangeItem: TMenuItem; HelpAboutItem: TMenuItem; OpenDialog: TOpenDialog; FileSaveItem: TMenuItem; FileSaveAsItem: TMenuItem; Edit1: TMenuItem; CutItem: TMenuItem; CopyItem: TMenuItem; PasteItem: TMenuItem; WindowMinimizeItem: TMenuItem; StatusBar: TStatusBar; {Компонент строки состояния} ActionList1: TActionList; {Компонент для определения списка именованных действий} EditCut1: TEditCut; {Компонент для копирования в буфер обмена} EditCopy1: TEditCopy; EditPaste1: TEditPaste; FileNew1: TAction; {Компонент именованного действия} FileSave1: TAction; FileExit1: TAction; FileOpen1: TAction; FileSaveAs1: TAction; WindowCascade1: TWindowCascade; WindowTileHorizontal1: TWindowTileHorizontal; WindowArrangeAll1: TWindowArrange; WindowMinimizeAll1: TWindowMinimizeAll; HelpAbout1: TAction; FileClose1: TWindowClose; WindowTileVertical1: TWindowTileVertical; WindowTileItem2: TMenuItem; ToolBar2: TToolBar; {Панель инструментов} ToolButton1: TToolButton; {Кнопки панели инструментов} ToolButton2: TToolButton; ToolButton3: TToolButton; ToolButton4: TToolButton; ToolButton5: TToolButton; ToolButton6: TToolButton; ToolButton9: TToolButton; ToolButton7: TToolButton; ToolButton8: TToolButton; ToolButton10: TToolButton; ToolButton11: TToolButton; ImageList1: TImageList; procedure FileNew1Execute(Sender: TObject); procedure FileOpen1Execute(Sender: TObject); procedure HelpAbout1Execute(Sender: TObject); procedure FileExit1Execute(Sender: TObject); end;

    Листинг 25.1.

    В коде модуля main. pas должно быть указано использование двух других модулей приложения: uses ChildWin, About;.

    Процедура создания нового документа или открытия существующего реализована следующим кодом:

    {Создать новый документ} procedure TMainForm.FileNew1Execute(Sender: TObject); begin {Создание дочернего окна с новым именем} CreateMDIChild('NONAME' + IntToStr(MDIChildCount + 1)); end; {Открыть документ} procedure TMainForm.FileOpen1Execute(Sender: TObject); begin if OpenDialog.Execute then {Выбор имени документа} CreateMDIChild(OpenDialog.FileName); {Создание окна} end; procedure TMainForm.CreateMDIChild(const Name: string); var Child: TMDIChild; begin { Класс TMDIChild определен в модуле CHILDWIN.PAS } Child := TMDIChild.Create(Application); {Создание окна} Child.Caption := Name; {Заголовком окна будет имя файла} if FileExists(Name) then // Дочернее окно содержит поле типа TMemo, в которое // выполняется загрузка текстового файла: Child.Memo1.Lines.LoadFromFile(Name); end; Для завершения приложения выполняется следующая процедура: procedure TMainForm.FileExit1Execute(Sender: TObject); begin Close; end; В модуле childwin.pas находится код дочерней формы: type TMDIChild = class(TForm) Memo1: TMemo; {Поле для отображения текста} procedure FormClose(Sender: TObject; var Action: TCloseAction); end; implementation procedure TMDIChild.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; end.

    Листинг 25.2.

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

    object MainForm: TMainForm Caption = 'Приложение с MDI-интерфейсом' FormStyle = fsMDIForm Menu = MainMenu1 WindowMenu = Window1 object StatusBar: TStatusBar AutoHint = True Panels = <> SimplePanel = True end object ToolBar2: TToolBar Images = ImageList1 object ToolButton9: TToolButton Action = FileNew1 {Именованное действие, которое будет выполнено при щелчке на кнопке} end object ToolButton1: TToolButton Action = FileOpen1 end {Кнопки панели инструментов} ...


    end object MainMenu1: TMainMenu Images = ImageList1 object File1: TMenuItem Caption = '&File' object FileNewItem: TMenuItem Action = FileNew1 end object FileOpenItem: TMenuItem Action = FileOpen1 end object FileCloseItem: TMenuItem Action = FileClose1 end ... object FileExitItem: TMenuItem Action = FileExit1 end end object Edit1: TMenuItem ... end object Window1: TMenuItem ... end end object OpenDialog: TOpenDialog {Диалог Open} Filter = 'All files (*.*)|*.*' end object ActionList1: TActionList object FileNew1: TAction Category = 'File' Caption = '& New' OnExecute = FileNew1Execute end object FileOpen1: TAction Category = 'File' Caption = '&Open' OnExecute = FileOpen1Execute end ... end end

    Листинг 25.3.

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

    object MDIChild: TMDIChild FormStyle = fsMDIChild Position = poDefault Visible = True OnClose = FormClose object Memo1: TMemo WordWrap = False end end

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

    Статическое и динамическое подключения DLL-библиотеки

    DLL-библиотека может подключаться или статически, или динамически. При подключении DLL-библиотеки она загружается в память приложения.
    При статическом подключении DLL-библиотека загружается один раз при запуске приложения.
    На всем протяжении выполнения приложения имя функции, импортируемой из DLL-библиотеки, которая была подключена статически, указывает на одну и ту же функцию (точку входа в DLL) в одной и той же DLL.
    В отличие от статического подключения DLL-библиотеки, выполняемого в момент загрузки приложения, динамическое подключение может быть выполнено в любой точке выполнения программы. После вызова функции из DLL-библиотеки ее можно отключить. При одновременном использовании нескольких DLL-библиотек это дает ощутимую экономию памяти.
    Для динамического подключения DLL-библиотеки применяются функции Windows API. Windows API - это набор стандартных функций, используемый для реализации взаимодействия с операционной системой.
    Все функции из статически подключаемой DLL-библиотеки, которые будут использоваться в приложении, первоначально должны быть объявлены как внешние.
    При этом следует указать, если требуется, модификатор вызова. Если функция вызывается по индексу, то для нее следует задать имя, используемое в приложении и индекс функции в DLL-библиотеке.
    Объявления внешних функций выполняется в секции implementation до использования этих функций.
    Объявление внешней функции с ключевым словом external определяет, что будет применено статическое связывание.
    Например:
    function F1 (i: Integer): Integer; stdcall; external 'MyLib.dll';
    При вызове функции из динамически подключаемой DLL-библиотеки, вместо определения имени функции как external, в случае статического связывания, следует определить новый тип, соответствующий типу вызываемой функции, и создать переменную данного типа.
    Определение типа функции или процедуры описывается так:
    Новый_тип =function(список_параметров):тип_функции; модификатор_доступа; или
    Новый_тип=procedure(список_параметров); модификатор доступа;.
    Следующий пример иллюстрирует вызов функции из динамически подключаемой DLL-библиотеки:
    unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button3: TButton; procedure Button3Click(Sender: TObject); end; TMyF1=function( i:Integer):Integer; stdcall; {Создание типа функции} var Form1: TForm1; MyF1 : TMyF1; {Объявление переменной типа функции} implementation {$R *.dfm} procedure TForm1.Button3Click(Sender: TObject); var h: Integer; begin h:=LoadLibrary('MyLib.dll'); // Динамическое подключение if h <> 0 then begin @MyF1:=GetProcAddress(h,'F1'); // Получение адреса функции if @MyF1 <> nil then ShowMessage(IntToStr(MyF1(20)); // Вызов Функции FreeLibrary(h); // Освобождение dll-библиотеки end; end; end.

    Введение в программирование

    Блоки прослушивания пакета JDK

    Пакет java.util содержит интерфейс EventListener, который наследуется всеми блоками прослушивания.
    Для различных классов компонентов предназначаются разные интерфейсы блоков прослушивания.
    В следующей таблице приведены некоторые интерфейсы блоков прослушивания, наследуемые от интерфейса EventListener.
    ИнтерфейсПакетОписание
    Actionjavax.swingРасширяет интерфейс ActionListener, позволяя нескольким компонентам использовать одни и те же обработчики событий
    ActionListenerjava.awt.eventЭтот блок прослушивания регистрируется методом addActionListener. При возникно- вении события "действие" вызывается метод actionPerformed(ActionEvent e) компонента, зарегистрировавшего данный блок прослушивания. Интерфейс исполь- зуется для обработки событий меню, кнопок и т.п.
    AdjustmentListenerjava.awt.eventИспользуется для получения регулируемых событий
    AncestorListenerjavax.swing.eventИнтерфейс поддерживает уведомления при изменении компонента класса JComponent или одного из его предков. Это касается перемещения компонента, перехода из видимого состояния в неви димое или обратно, выполнения метода setVisible(), а также при добавлении и удалении компонентов из иерархии
    CaretListenerjavax.swing.eventИспользуется при изменении позиции ввода в текстовых компонентах. Этот интерфейс реализован классом javax.swing.text.JTextComponent.AccessibleJTextComponent
    CaretListenerjavax.swing.eventИспользуется при изменении позиции ввода в текстовых компонентах. Этот интерфейс реализован классом javax.swing.text.JTextComponent.AccessibleJTextComponent
    CellEditorListenerjavax.swing.eventИспользуется для отслеживания изме нений в редактируемой ячейке (CellEditor), касающихся завершения или отмены редактирования. Этот интерфейс реализован следующими классами: JTable, JTable.AccessibleJTable, BasicTreeUI.CellEditorHandler
    ChangeListenerjavax.swing.eventОпределяет объект, выполняющий прослушивание событий ChangeEvent. Интерфейс объявляет всего один метод: void stateChanged(ChangeEvent e). Этот интерфейс реализован несколькими классами, включая: JMenuItem.AccessibleJMenuItem, BasicButtonListener, JTabbedPane.AccessibleJTabbedPane.
    ContainerListenerjava.awt.eventИнтерфейс объявляет два метода: public void componentAdded(ContainerEvent e) и public void componentRemoved(ContainerEvent e), вызываемые при добавлении компонента в контейнер или при удалении из контейнера. Для этого интерфейса реализован класс-адаптер ContainerAdapter
    DocumentListenerjavax.swing.eventИнтерфейс используется при изменении текстового документа
    DragGestureListenerjava.awt.dndИнтерфейс используется при инициа- лизации процесса перетаскивания объекта
    DragSourceListenerjava.awt.dndИнтерфейс используется для реализации механизма перетаскивания и сброса- объектов (Drag & Drop). В этот интер- фейсе объявлены методы для отслежи- вания действий пользователя по пере- мещению объекта. Этот интерфейс реализован классом DragSourceContext
    DropTargetListenerjava.awt.dndИнтерфейс может быть использован для обработки событий, инициируемых в то время, когда объект находится над местом сброса
    FocusListenerjava.awt.eventИнтерфейс используется для обработки событий получения или потери фокуса компонентом. Блок прослушивания регистрируется методом addFocusListener. Для этого интерфейса реализован класс адаптер FocusAdapter
    ItemListenerjava.awt.eventИнтерфейс используется для обработки события выделения элемента и объяв- ляет только один метод public void itemStateChanged(ItemEvent e). Блок прослушивания регистрируется методом addItemListener
    KeyListenerjava.awt.eventИнтерфейс используется для обработки событий от клавиатуры. Блок прослу- шивания регистрируется методом addKeyListener. Для интерфейса реали- зован класс-адаптер KeyAdapter
    ListSelectionListenerjavax.swing.eventИспользуется для обработки события, инициирующегося при изменении области выделения
    MenuDragMouseListenerjavax.swing.eventИнтерфейс объявляет четыре метода обработчика событий, инициируемых при перемещении и сбросе в области компонентов меню
    MenuKeyListenerjavax.swing.eventИнтерфейс используется для обработки событий, инициируемых для меню при вводе комбинаций клавиш
    MenuListenerjavax.swing.eventОпределяет блок прослушивания с обработчиками событий для меню
    MouseInputListenerjavax.swing.eventИнтерфейс наследует интерфейсам MouseMotionListener (методы: mouseDragged, mouseMoved) и MouseListener (методы: mouseClicked, mouseEntered, mouseExited, mousePressed, mouseReleased). Этот интерфейс используется для обработки любых событий, инициируемых действиями мыши
    MouseListenerjava.awt.eventИнтерфейс, используемый для обработки событий от щелчков мышью. Блок прослушивания регистрируется методом addMouseListener. Для интерфейса реализован класс-адаптер MouseAdapter
    MouseMotionListenerjava.awt.eventИнтерфейс, используемый для обработки событий от перемещения курсора мыши. Блок прослушивания регистри руется методом addMouseMotionListener. Для интерфейса реализован класс-адаптер MouseMotionAdapter.
    PopupMenuListenerjavax.swing.eventИнтерфейс определяет методы блока прослушивания для всплывающих меню (popup-меню).
    PropertyChangeListenerjava.beansИнтерфейс определяет метод обработчик события, вызываемый при изменении свойства бина
    TableColumnModelListenerjavax.swing.eventИнтерфейс, используемый для прослу шивания событий, изменяющих TableColumnModel. К таким событиям относятся добавление, удаление, изменение размера и перемещение столбца таблицы. Этот интерфейс реализован классами JTable, JTable.AccessibleJTable и JTableHeader
    TableModelListenerjavax.swing.eventИнтерфейс, используемый для прослу шивания событий, которые изменяют TableModel
    TextListenerjava.awt.eventИнтерфейс объявляет метод void textValueChanged(TextEvent e), вызываемый при изменении значения текстовых компонентов, таких, как TextArea, TextField
    TreeExpansionListenerjavax.swing.eventИнтерфейс, используемый для прослу шивания событий распахивания или сворачивания дерева
    TreeModelListenerjavax.swing.eventИнтерфейс, используемый для прослу шивания событий, которые изменяют TreeModel
    TreeSelectionListenerjavax.swing.eventИнтерфейс объявляет метод, вызываемый при изменении выделенного элемента дерева
    WindowListenerjava.awt.eventИнтерфейс используется для обработки событий окна. Блок прослушивания регистрируется методом addWindowListener. Для интерфейса реализован класс-адаптер WindowAdapter


    Блоки прослушивания

    В настоящее время в языке Java используется модель ожидаемых событий. В этой модели инициируются только те события, которые были объявлены объектами как ожидаемые.
    Объект регистрирует блок прослушивания событий. Блок прослушивания - это интерфейс, который определяет набор методов-обработчиков событий, объявленных как ожидаемые события.
    Регистрация блока прослушивания для компонента состоит в вызове метода, начинающегося с префикса add, за которым идет имя блока прослушивания. Имена блоков прослушивания оканчиваются суффиксом Listener.
    Для одного компонента можно зарегистрировать только один блок прослушивания. Но один блок прослушивания может использоваться несколькими компонентами одновременно.
    Для того, чтобы компонент мог обрабатывать поступающие для него события, следует:
  • при объявлении класса указать наследуемые этим классом интерфейсы, содержащие методы-обработчики событий;
  • добавить блоки прослушивания для компонентов;
  • все методы-обработчики, объявленные в наследуемом интерфейсе, реализовать в классе компонента.

  • Любой метод блока прослушивания имеет один параметр - объект, производный от класса EventObject.
    В классе EventObject определен метод Object getSource(), возвращающий объект, который инициировал событие. Некоторые классы, производные от EventObject, имеют свои методы, которые определяют объект, инициировавший событие. Например, класс ComponentEvent определяет метод getComponent, возвращающий объект Component.

    Классы-адаптеры

    Чтобы зарегистрировать блок прослушивания, нужно указать его в объявлении класса как наследуемый. В результате этого класс, наследующий данный интерфейс, должен содержать код реализации всех объявленных в интерфейсе методов. Если таких методов много, а нужен только один, то все равно приходится включать код реализации каждого объявленного в интерфейсе метода. Альтернативой такому подходу служит применение классов адаптеров.
    Класс-адаптер для интерфейса блока прослушивания содержит "пустую" реализацию всех его методов. Таким образом, при создании класса, как производного от класса-адаптера, в качестве блока прослушивания можно указывать класс-адаптер и включать реализацию только необходимых методов.
    На следующей схеме приведен пример обработки события "щелчок мышью" двумя способами: с применением интерфейса блока прослушивания и с применением адаптера блока прослушивания.
    Применение интерфейса:Применение класса адаптера:

    public class MyClass implements MouseListener { ... myObject.addMouseListener(this); ... /* Реализация всех методов интерфейса MouseListener */ public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseClicked(MouseEvent e) { ...// Код метода } }

    public class MyClass extends MouseAdapter { ... myObject.addMouseListener(this); ... /* Переопределение только одного метода адаптера MouseAdapter */ public void mouseClicked(MouseEvent e) } ...// Код переопределяемого метода } }

    Приведенный выше пример в практическом плане имеет один недостаток. При программировании классы приложений в большинстве случаев создаются как производные от классов Frame, Panel, JFrame, а классы апплетов - от класса Applet или JApplet. Но в языке Java реализовано только простое наследование, позволяющее иметь всего один наследуемый класс.
    Поэтому, чтобы применять классы-адаптеры, можно использовать два способа реализации:
  • использование внутренних классов: public class MyClass extends Applet { ... // Создание объекта класса адаптера: myObject.addMouseListener(new MyClassAdapter()); ...
    class MyClassAdapter extends MouseAdapter {//Объявление // внутреннего класса адаптера public void mouseClicked(MouseEvent e) { ... } // Реализация методов класса адаптера } }

  • использование анонимных внутренних классов:

    public class MyClass extends Applet { ... // Создание объекта и реализация класса адаптера: myObject.addMouseListener(new MouseAdapter() { // Реализация переопределяемых методов класса адаптера public void mouseClicked(MouseEvent e) { } }); } }



  • Для того чтобы реализовать применение класса-адаптера с использованием вложенного класса, следует:

  • добавить блок прослушивания компонента и указать в качестве параметра код new имя_внутреннего_класса (например, addMouseListener(new MouseAdapter() );
  • добавить код с объявлением внутреннего класса, включающий реализацию требуемых методов обработчиков событий (например, class MyClassAdapter extends MouseAdapter { public void mouseClicked(MouseEvent e) { ѕ }}.)


  • Для того чтобы реализовать применение класса адаптера с использованием вложенного анонимного класса-адаптера, следует:

  • добавить блок прослушивания компонента и указать в качестве параметра код new имя_класса_адаптера { } (например, addMouseListener(new MyClassAdapter(){ });
  • вставить в фигурные скобки после имени класса адаптера код переопределяемых методов (например, { public void mouseClicked(MouseEvent e) { ѕ }}).


  • Использование анонимных вложенных классов значительно улучшает читаемость кода.

    События действия

    Событие действия - это семантические событие, зависящее от типа компонента. Так, для командной кнопки событием действия будет щелчок мышью или нажатие клавиши Enter в момент, когда кнопка имеет фокус. Для компонентов типа "список" событием действия является выбор элемента, для компонентов "меню" - выбор пункта меню, а для компонентов "текстовое поле" - нажатие клавиши Enter.
    События действия определяются в интерфейсе ActionListener. Этот интерфейс задает единственный метод обработки события actionPerformed, вызываемый при возникновении для компонента сооответствующего его типу события действия.
    Для того чтобы обрабатывать событие действия, можно выполнить следующее:
  • Создать класс, наследующий интерфейс ActionListener. Например:
    public class MyFrame extends Frame implements ActionListener { }.
  • Зарегистрировать блок прослушивания события действия для компонента. Например:
    myButton.addActionListener(this).
  • Переопределить метод actionPerformed: Например:
    public void actionPerformed(ActionEvent e) { Toolkit.getDefaultToolkit().beep(); }.

  • Метод обработки события действия получает параметр типа ActionEvent.
    Класс ActionEvent определен в иерархии классов Java следующим образом:
    События действия

    Класс ActionEvent определяет и наследует несколько полезных методов, включая следующие:
  • GetActionCommand - метод возвращает строку, ассоциируемую с данным событием действия. Если для объекта был ранее вызван метод setActionCommand, устанавливающий такую строку, то эта строка и будет возвращена. В противном случае, возвращаемое значение зависит от типа компонента/
  • GetModifiers - возвращает число, определяющее, была ли нажата клавиша-модификатор при возникновении события действия. Для определения кода нажатой клавиши-модификатора можно использовать константы SHIFT_MASK, CTRL_MASK и ALT_MASK.Например, если при возникновении события действия была нажата клавиша Shift, то следующее выражение не будет равно нулю:
    actionEvent.getModifiers() & ActionEvent. SHIFT_MASK.
  • getSource - метод возвращает объект, для которого было инициировано событие.

  • События действия

    События окна

    Методы - обработчики событий окна объявляются в интерфейсе WindowListener . Для данного интерфейса существует класс адаптер WindowAdapter .
    Для того чтобы отслеживать все события окна, можно создать класс окна, наследуемый от интерфейса WindowListener.
    Например:
    public class MyWindowListener extends Frame implements WindowListener { public void windowClosing(WindowEvent e) { } public void windowClosed(WindowEvent e) { } public void windowOpened(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowActivated(WindowEvent e) { } public void windowDeactivated(WindowEvent e) { } }
    Если надо отслеживать все события окна приложения или апплета, то блок прослушивания следует добавить для объекта this/.
    Например:
    addWindowListener(this);
    Если надо отслеживать все события окна, создаваемого в процессе выполнения приложения или апплета, то сначала надо создать объект "окно", а затем добавить для него блок прослушивания.
    Например:
    myFrame = new Frame("Заголовок окна"); myFrame.addWindowListener(this);
    Интерфейс WindowListene объявляет следующие методы, вызываемые для события WindowEvent:
  • WindowActivated - метод обработки события, вызываемый при активизации окна пользователем.
  • WindowClosed - метод обработки события, вызываемый при закрытии окна вследствии вызова метода dispose(), который освобождает ресурсы экрана.
  • WindowClosing - метод обработки события, вызываемый при закрытии окна пользователем с помощью системного меню.
  • WindowDeactivated - метод обработки события, вызываемый при потери окном фокуса.
  • windowDeiconified - метод обработки события, вызываемый при изменении состояния окна из свернутого в нормальное.
  • windowIconified - метод обработки события, вызываемый при изменении состояния окна из нормального в свернутое.
  • windowOpened- метод вызывается один раз при открытии окна.


  • События от клавиатуры

    Методы обработчики событий от клавиатуры объявляются в интерфейсе KeyListener, для которого существует класс адаптер KeyAdapter.
    Событие от клавиатуры происходит для компонента, имеющего фокус. События от клавиатуры являются низкоуровневыми событиями.
    Интерфейс KeyListener объявляет следующие методы обработчики для события KeyEvent:
    o void keyTyped(KeyEvent e); // Ввод символа o void keyPressed(KeyEvent e); // Нажатие клавиши o void keyReleased(KeyEvent e) // Отпускание клавиши
    Для получения информации о коде нажатой клавиши следует использовать методы класса KeyEvent.
    Класс KeyEvent определен в иерархии классов Java следующим образом:
    События от клавиатуры

    При нажатии или отпускании клавиши метод getKeyCode возвращает значение кода нажатой клавиши.
    Метод getKeyChar возвращает значение символа Unicode или CHAR_UNDEFINED.
    При обработки события ввода (метод void keyTyped(KeyEvent e) ) можно получить значение введенного с клавиатуры символа в формате Unicode или CHAR_UNDEFINED.
    Клавиатурные комбинации обрабатываются в методах:
  • void keyPressed(KeyEvent e) и
  • void keyReleased(KeyEvent e)

  • Например, нажатие клавиш Shift+B можно отследить в методе keyPressed (событие KEY_PRESSED): при первом вызове метода будет возвращен код клавиши Shift - VK_SHIFT, а при втором вызове метода - код клавиши A - VK_B. И только затем произойдет вызов метода keyTyped.
    На следующей схеме приведен алгоритм обработки событий от клавиатуры.
    Нажатая клавишаВызываемые методы обработки событияМетоды класса KeyEvent,используемые для получения информацииВозвращаемое методом значение
    Shift+AkeyPressedgetKeyChar()
    getKeyCode()
    getModifiers()
    символ = ' '
    код = 16 (Shift)
    модификатор = 1
    keyPressedgetKeyChar()
    getKeyCode()
    getModifiers()
    символ ='B'
    код = 66(B)
    модификатор = 1
    keyTypedgetKeyChar()
    getKeyCode()
    getModifiers()
    символ ='B'
    код = 0
    модификатор = 0
    keyReleasedgetKeyChar()
    getKeyCode()
    getModifiers()
    символ ='A'
    код = 66(B)
    модификатор = 0
    keyReleasedgetKeyChar()
    getKeyCode()
    getModifiers()
    символ = ' '
    код = 16 (Shift)
    модификатор = 0
    <
    В классе KeyEvent определены виртуальные коды для всех клавиш клавиатуры. К таким кодам относятся:
  • Коды цифр: от VK_0 до VK_9 ( ASCII-коды цифр от '0' до '9' (0x30 - 0x39)).
  • Коды букв: от VK_A до VK_Z (ASCII-коды букв от 'A' до 'Z' (0x41 - 0x5A)).
  • Коды NUMPAD-клавиатуры: от VK_NUMPAD0 до VK_NUMPAD9.
  • Коды управляющих и функциональных клавиш: от VK_F1 до VK_F24, VK_NUM_LOCK, VK_PRINTSCREEN, VK_INSERT, VK_HELP, VK_DELETE, VK_ENTER, VK_BACK_SPACE, VK_TAB, VK_CANCEL, VK_CAPS_LOCK, VK_ESCAPE, VK_SPACE, VK_PAUSE.
  • Коды перемещения позиции: VK_PAGE_UP, VK_PAGE_DOWN, VK_END, VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN.
  • Коды-модификаторы: VK_SHIFT, VK_ALT, VK_CONTROL.
  • Коды символов: VK_DOLLAR, VK_COMMA, VK_MINUS, VK_PERIOD, VK_SLASH, VK_SEMICOLON, VK_EQUALS, VK_OPEN_BRACKET (открывающая скобка), VK_BACK_SLASH (обратный слэш), VK_CLOSE_BRACKET (закрывающая скобка).

  • Класс KeyEvent содержит следующий набор методов, предназначенных для определения кодов нажатых клавиш:
  • GetKeyChar - возвращает символ Unicode, соответствующий нажатой клавиши, с учетом регистра и языка клавиатуры.
  • GetKeyCode - возвращает код нажатой клавиши.
  • GetKeyModifiersText - возвращает строку, содержащую описание кода-модификатора (например, "Ctrl+Shift").
  • GetKeyText - возвращает строку, содержащую описание кода (например, "F1", "PageUp" или "D").
  • IsActionKey - определяет, была ли нажата клавиша action-ключа, такая, как PGUP, PGDN, F1, F2 и т.п.
  • ParamString - возвращает строку параметров, определяющих данное событие.
  • SetKeyChar - устанавливает значение, равное значению символа Unicode.
  • SetKeyCode - устанавливает значение, равное значению кода клавиши.
  • SetModifiers - устанавливает значение кода модификатора.
  • SetSource- определяет источник события KeyEvent.

  • Наряду с описанными методами, можно использовать методы, наследуемые от класса java.awt.event.InputEvent, включая следующие:
  • boolean isAltDown() // Нажата клавиша Alt
  • boolean isShiftDown() // Нажата клавиша Shift
  • boolean isControlDown() // Нажата клавиша Ctrl


  • Типы событий

    Событием в языке Java является объект. Все события можно разделить на две группы: события низкого уровня и семантические события.
    К событиям низкого уровня относятся:
  • события от клавиатуры и мыши;
  • события от окна Windows;
  • события от компонента;
  • события от контейнера;
  • события от перемещения фокуса ввода.

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

    Введение в программирование

    public class Frame1 extends JPanel

    import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Frame1 extends JPanel { JSplitPane jSplitPane1 = new JSplitPane(); // Класс // разделяемых панелей JScrollPane jScrollPane1 = new JScrollPane(); JScrollPane jScrollPane2 = new JScrollPane(); JTextPane jTextPane1 = new JTextPane(); JTextPane jTextPane2 = new JTextPane(); public Frame1() { try { jbInit(); } catch(Exception e) { } } public static void main(String s[]) { JFrame frame = new JFrame("Панели"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setContentPane(new Frame1()); frame.pack(); frame.setVisible(true); } private void jbInit() throws Exception { // Определение ориентации разделяемых панелей jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); // Размещение левого и правого компонента // на разделяемой панели jSplitPane1.setLeftComponent(jScrollPane1); jSplitPane1.setRightComponent(jScrollPane2); // Отображение кнопок сворачивания и разворачивания // сторон разделяемой панели jSplitPane1.setOneTouchExpandable(true); // Задание размера панелей jScrollPane1.setPreferredSize(new Dimension(300, 60)); jScrollPane2.setPreferredSize(new Dimension(300, 60)); // Добавление разделяемой панели к окну формы this.add(jSplitPane1, null); // Добавление компонентов в контейнеры // типа JScrollPane jScrollPane1.getViewport().add(jTextPane1, null); jScrollPane2.getViewport().add(jTextPane2, null); } }

    Листинг 27.1.
    Закрыть окно





    import java.awt.*;

    import java.awt.event.*;

    import javax.swing.*;

    public class Frame1 extends JPanel {

    JSplitPane jSplitPane1 = new JSplitPane(); // Класс

    // разделяемых панелей

    JScrollPane jScrollPane1 = new JScrollPane();

    JScrollPane jScrollPane2 = new JScrollPane();

    JTextPane jTextPane1 = new JTextPane();

    JTextPane jTextPane2 = new JTextPane();

    public Frame1() { try { jbInit(); }

    catch(Exception e) { } }

    public static void main(String s[]) {

    JFrame frame = new JFrame("Панели");

    frame.addWindowListener(new WindowAdapter() {

    public void windowClosing(WindowEvent e) {

    System.exit(0); } });

    frame.setContentPane(new Frame1());

    frame.pack();

    frame.setVisible(true);

    }

    private void jbInit() throws Exception {

    // Определение ориентации разделяемых панелей

    jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT);

    // Размещение левого и правого компонента

    // на разделяемой панели

    jSplitPane1.setLeftComponent(jScrollPane1);

    jSplitPane1.setRightComponent(jScrollPane2);

    // Отображение кнопок сворачивания и разворачивания

    // сторон разделяемой панели

    jSplitPane1.setOneTouchExpandable(true);

    // Задание размера панелей

    jScrollPane1.setPreferredSize(new Dimension(300, 60));

    jScrollPane2.setPreferredSize(new Dimension(300, 60));

    // Добавление разделяемой панели к окну формы

    this.add(jSplitPane1, null);

    // Добавление компонентов в контейнеры

    // типа JScrollPane

    jScrollPane1.getViewport().add(jTextPane1, null);

    jScrollPane2.getViewport().add(jTextPane2, null);

    }

    }

    public class MyApplet extends Applet

    import java.applet.Applet; import java.awt.*; public class MyApplet extends Applet { Panel panel1 = new Panel(); GridLayout gridLayout1 = new GridLayout(); // Создание новой кнопки: Checkbox checkbox1 = new Checkbox(); Checkbox checkbox2 = new Checkbox();

    GridLayout gridLayout2 = new GridLayout(); Panel panel2 = new Panel(); // Создание группы кнопок: CheckboxGroup checkboxGroup1 = new CheckboxGroup(); Checkbox checkbox4 = new Checkbox(); Checkbox checkbox5 = new Checkbox(); Checkbox checkbox6 = new Checkbox(); FlowLayout FlowLayout1 = new FlowLayout(); public MyApplet() { try { jbInit(); } catch(Exception e) { } } public static void main(String[] args) { MyApplet myApplet1 = new MyApplet(); } private void jbInit() throws Exception { setLayout(gridLayout2); panel1.setLayout(gridLayout1); checkbox1.setLabel("Флажок 1"); checkbox2.setLabel("Флажок 2"); checkbox2.setState(true); // Состояние флажка - // включен gridLayout2.setRows(2); panel2.setLayout(FlowLayout1); // Добавление в группу трех кнопок: checkbox4.setCheckboxGroup(checkboxGroup1); checkbox4.setLabel("Радиокнопка 1"); checkbox4.setState(true); // Состояние радиокнопки - // включена checkbox5.setCheckboxGroup(checkboxGroup1); checkbox5.setLabel("Радиокнопка 2"); checkbox6.setCheckboxGroup(checkboxGroup1); checkbox6.setLabel("Радиокнопка 3"); // Добавление кнопок в контейнеры - панели this.add(panel1, null); panel1.add(checkbox1, null); panel1.add(checkbox2, null); this.add(panel2, null); panel2.add(checkbox4, null); panel2.add(checkbox5, null); panel2.add(checkbox6, null); } }

    Листинг 27.2.
    Закрыть окно





    import java.applet.Applet;

    import java.awt.*;

    public class MyApplet extends Applet {

    Panel panel1 = new Panel();

    GridLayout gridLayout1 = new GridLayout();

    // Создание новой кнопки:

    Checkbox checkbox1 = new Checkbox();

    Checkbox checkbox2 = new Checkbox();



    GridLayout gridLayout2 = new GridLayout();

    Panel panel2 = new Panel();

    // Создание группы кнопок:

    CheckboxGroup checkboxGroup1 = new CheckboxGroup();

    Checkbox checkbox4 = new Checkbox();

    Checkbox checkbox5 = new Checkbox();

    Checkbox checkbox6 = new Checkbox();

    FlowLayout FlowLayout1 = new FlowLayout();

    public MyApplet() {

    try { jbInit(); } catch(Exception e) { }

    }

    public static void main(String[] args) {

    MyApplet myApplet1 = new MyApplet(); }

    private void jbInit() throws Exception {

    setLayout(gridLayout2);

    panel1.setLayout(gridLayout1);

    checkbox1.setLabel("Флажок 1");

    checkbox2.setLabel("Флажок 2");

    checkbox2.setState(true); // Состояние флажка -

    // включен

    gridLayout2.setRows(2);

    panel2.setLayout(FlowLayout1);

    // Добавление в группу трех кнопок:

    checkbox4.setCheckboxGroup(checkboxGroup1);

    checkbox4.setLabel("Радиокнопка 1");

    checkbox4.setState(true); // Состояние радиокнопки -

    // включена

    checkbox5.setCheckboxGroup(checkboxGroup1);

    checkbox5.setLabel("Радиокнопка 2");

    checkbox6.setCheckboxGroup(checkboxGroup1);

    checkbox6.setLabel("Радиокнопка 3");

    // Добавление кнопок в контейнеры - панели

    this.add(panel1, null);

    panel1.add(checkbox1, null);

    panel1.add(checkbox2, null);

    this.add(panel2, null);

    panel2.add(checkbox4, null);

    panel2.add(checkbox5, null);

    panel2.add(checkbox6, null);

    }

    }

    к элементам списка через модель

    String[] data = {"один", "два", "три"}; // Массив строк JList jList1 = new JList(data); // Создание списка, // содержащего массив строк // Доступ к элементам списка через модель for(int i = 0; i
    Листинг 27.3.
    Закрыть окно





    String[] data = {"один", "два", "три"}; // Массив строк

    JList jList1 = new JList(data); // Создание списка,

    // содержащего массив строк

    // Доступ к элементам списка через модель

    for(int i = 0; i

    System.out.println(jList1.getModel().getElementAt(i)); }

    // Заполнение списка данными, представляемыми классом Vector

    JList jList1 = new JList();

    Vector superClasses = new Vector();

    Class rootClass = javax.swing.JList.class; // Создание объекта

    // типа Class

    for(Class cls = rootClass; cls != null;

    cls = cls.getSuperclass())

    { // Получение всех подклассов

    superClasses.addElement(cls); }

    jList1.setListData(superClasses); // Заполнение компонента jList1

    // списком всех его подклассов

    // Добавление элементов в список, хранимый в объекте типа Vector

    superClasses.addElement(new String("12345"));

    // Выделение элементов списка:

    jList1.setSelectedIndex(1); // Выделение второго элемента списка

    jList1.getSelectedValue(); // Возвращает строку, отображаемую

    //во втором элементе списка

    Класс BorderLayout

    Менеджер компоновки BorderLayout разбивает контейнер на пять областей и располагает добавляемые в контейнер объекты по краям (север, юг, запад, восток) и в центре.
    Каждая область указывается соответствующей константой: NORTH, SOUTH, EAST, WEST и CENTER. Если в методе add отсутствует строка, указывающая расположение компонента, то по умолчанию используется значение CENTER.
    На рис. 27.1. приведен внешний вид, реализуемый менеджером компоновки BorderLayout для пяти кнопок, которые расположены в контейнере - апплете.
    Класс BorderLayout
    Рис. 27.1.  Менеджер компоновки BorderLayout
    Следующий код иллюстрирует использование компоновки BorderLayout:
    import java.applet.Applet; import java.awt.*; public class MyApplet extends Applet { public MyApplet() { try { jbInit();} catch(Exception e) { } } public static void main(String[] args) { MyApplet myApplet1 = new MyApplet(); } private void jbInit() throws Exception { setLayout(new BorderLayout()); add(new Button("North"), BorderLayout.NORTH); add(new Button("South"), BorderLayout.SOUTH); add(new Button("East"), BorderLayout.EAST); add(new Button("West"), BorderLayout.WEST); add(new Button("Center"), BorderLayout.CENTER); } }
    Класс BorderLayout предоставляет ряд методов, включая следующие:
  • GetHgap - возвращает расстояние в пикселях между компонентами по горизонтали.
  • SetHgap - устанавливает расстояние в пикселях между компонентами по горизонтали.
  • GetVgap - возвращает расстояние в пикселях между компонентами по вертикали.
  • SetVgap - устанавливает расстояние в пикселях между компонентами по вертикали.


  • Класс CardLayout

    Класс CardLayout определяет менеджер компоновки для контейнера, который может содержать несколько страниц ("карт") и для которого одновременно может быть видна только одна карта.
    Класс CardLayout предоставляет ряд методов, включая следующие:
  • GetHgap- определяет отступ по горизонтали.
  • GetVgap - определяет отступ по вертикали.
  • First - активизирует первую страницу контейнера.
  • Last - активизирует последнюю страницу контейнера.
  • Next - активизирует следующую страницу контейнера в циклическом порядке (после последней карты активизируется первая карта).
  • Previous - активизирует предыдущую страницу контейнера в циклическом порядке.
  • Show - активизирует компонент указанного контейнера.

  • Например:
    // Для контейнера типа JPanel void jButton1_actionPerformed(ActionEvent e) { ((CardLayout)jPanel1.getLayout()).next(jPanel1); } // Для контейнера типа Panel void button1_actionPerformed(ActionEvent e) { cardLayout1.next(panel1); }

    Класс FlowLayout

    Менеджер компоновки FlowLayout размещает добавляемые в контейнер компоненты последовательно слева направо. Компоненты могут быть размещены в нескольких последовательных рядах.
    На рис. 27.2 приведены два результата применения этой компоновки при изменении размеров контейнера.
    Класс FlowLayout
    Рис. 27.2.  Применение компоновки FlowLayout
    Класс FlowLayout предоставляет следующие константы, определяющие выравнивание компонентов:
  • CENTER - по центру.
  • LEFT - по левому краю.
  • RIGHT - по правому краю.

  • Класс FlowLayout предоставляет ряд методов, включая следующие:
  • SetAlignment - устанавливает выравнивание компонентов для данной компоновки. Параметр метода может принимать следующие значения: FlowLayout.LEFT, FlowLayout.RIGHT и FlowLayout.CENTER.
  • GetHgap - определяет расстояние между компонентами по горизонтали.
  • SetHgap - устанавливает расстояние между компонентами по горизонтали.
  • GetVgap - определяет расстояние между компонентами по вертикали.
  • SetVgap- устанавливает расстояние между компонентами по вертикали.


  • Класс GridBagLayout

    Этот класс используется менеджером компоновки GridBagLayout и определяет требования к размещению компонентов.
    Компоновка GridBagLayout позволяет размещать компоненты в ячейках таблицы. Но, в отличие от менеджера компоновки GridLayout, ячейки таблицы могут различаться как по ширине, так и по высоте. Размещаемые компоненты могут занимать несколько ячеек.
    Область, занимаемая компонентом, называется областью отображения. Ее размеры определяются значениями переменных gridwidth и gridheight (количество ячеек по горизонтали и по вертикали) класса GridBagConstraints.
    Отступами (insets) называется расстояние между областью отображения и действительной областью, занимаемой компонентом.
    На рис. 27.4 приведен пример компоновки, в которой кнопка 3 занимает 9 ячеек, но размер кнопки меньше размера области отображения.
    Класс GridBagLayout
    Рис. 27.4.  Отступы, устанавливаемые объектом GridBagConstraints
    Если область отображения отличается от размера компонента, то для определения требований к размещению используется переменная fill.
    Если размер размещаемого компонента меньше размера области отображения, то для указания размещения компонента используется переменная anchor, которая может принимать одно из следующих значений:
  • GridBagConstraints.CENTER
  • GridBagConstraints.NORTH
  • GridBagConstraints.NORTHEAST
  • GridBagConstraints.EAST
  • GridBagConstraints.SOUTHEAST
  • GridBagConstraints.SOUTH
  • GridBagConstraints.SOUTHWEST
  • GridBagConstraints.WEST
  • GridBagConstraints.NORTHWEST.

  • Переменная fill класса GridBagConstraint определяет, следует ли изменять размер компонента, и может принимать следующие значения:
  • GridBagConstraint.NONE - размер компонента не изменять (значение, используемое по умолчанию);
  • GridBagConstraint.HORIZONTAL - изменить размер по горизонтали, но не изменять его высоту;
  • GridBagConstraint.VERTICAL - изменить размер по вертикали, но не изменять его ширину;
  • GridBagConstraint.BOTH - увеличить размеры компонента до размера области отображения.

  • Переменные gridheight и gridwidthкласса GridBagConstraint определяют число ячеек в столбце или строке соответственно. При этом константа GridBagConstraints.REMAINDER указывает, что компонент будет последним в столбце (строке), а константа GridBagConstraints.RELATIVE указывает, что компонент будет ближайшим к последнему.
    Конструктор GridBagConstraints(int gridx, int gridy, int gridwidth, int gridheight, double weightx, double weighty, int anchor, int fill, Insets insets, int ipadx, int ipady) создает объект требований к размещению компонента, используемый менеджером компоновки, со всеми полями, имеющими заданные значения.

    Класс GridLayout

    Этот класс позволяет размещать компоненты в контейнере в виде таблицы. В каждой ячейке таблицы может быть размещен только один компонент.
    Размер всех ячеек таблицы одинаков. Количество строк и столбцов таблицы определяется или в конструкторе, или вызовом методов setColumns и setRows. При этом, если эти значения не равны нулю, то количество столбцов является величиной вычисляемой и зависит от общего числа компонентов, добавленных на компоновку, и указанного числа строк. И только в том случае, если количество строк задано равным нулю, заданное количество столбцов будет учитываться менеджером компоновки.
    На рис. 27.3 приведены примеры использования компоновки GridLayout.
    Класс GridLayout
    Рис. 27.3.  Пример компоновки GridLayout
    Для компоновки GridLayout следует определять или количество строк, или количество столбцов.
    Например:
    this.setLayout(gridLayout1); gridLayout1.setRows(3);

    Кнопки

    Кнопки могут располагаться в контейнере как отдельно, так и в группе.
    Пакет java.awt содержит следующие классы кнопок и групп:
  • Button - командная кнопка.
  • Checkbox - флажок или радиокнопка (переключатель).
  • CheckboxGroup - группа кнопок.

  • Пакет облегченных swing-компонентов также предоставляет несколько классов кнопок и групп, включая следующие классы:
  • JButton - кнопка.
  • JRadioButton - радиокнопка.
  • JToggleButton - кнопка-переключатель.
  • JCheckBox - флажок
  • ButtonGroup - группа кнопок.

  • На кнопках из пакета javax.swing помимо метки может также отображаться и пиктограмма.
    Класс Button позволяет создавать объекты "командные кнопки". При нажатии на кнопку JVM инициирует событие действия actionPerformed. Наряду с данным семантическим событием, инициируется ряд простых событий, таких как mouseClicked.
    Класс Button предоставляет ряд методов, включая следующие:
  • AddActionListener - регистрирует блок прослушивания для события действия от командной кнопки;
  • GetActionCommand - возвращает имя команды, инициировавшей событие действия, или метку кнопки, если имя команды равно null (значение по умолчанию);
  • GetLabel - возвращает метку командной кнопки или null для непомеченной командной кнопки;
  • SetLabel - изменяет метку командной кнопки.

  • Класс Checkbox позволяет создавать компоненты кнопки двух типов, называемые флажками и радиокнопками. Такой компонент может иметь два состояния: включено (true) и выключено (false). Каждый щелчок на компоненте изменяет его состояние на обратное.
    Несколько переключателей могут быть объединены в группу, используя компонент CheckboxGroup, являющийся контейнером. Такая группа называется группой радиокнопок. Только один компонент группы может одновременно иметь состояние "включен".
    Для обработки событий от кнопки используется интерфейс ItemListener. Этот интерфейс определяет всего один обработчик события - метод itemStateChanged (ItemEvent e).
    Класс ItemEvent содержит метод getStateChange, позволяющий определить состояние кнопки. Метод может возвращать одно из двух возможных значений:

  • ItemEvent.SELECTED;
  • ItemEvent.DESELECTED.


  • Например:

    // Определение состояния кнопки void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { // Кнопка находится во включенном состоянии } }

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

    Следующий листинг иллюстрирует создание флажков и группы радиокнопок:

    import java.applet.Applet; import java.awt.*; public class MyApplet extends Applet { Panel panel1 = new Panel(); GridLayout gridLayout1 = new GridLayout(); // Создание новой кнопки: Checkbox checkbox1 = new Checkbox(); Checkbox checkbox2 = new Checkbox();

    GridLayout gridLayout2 = new GridLayout(); Panel panel2 = new Panel(); // Создание группы кнопок: CheckboxGroup checkboxGroup1 = new CheckboxGroup(); Checkbox checkbox4 = new Checkbox(); Checkbox checkbox5 = new Checkbox(); Checkbox checkbox6 = new Checkbox(); FlowLayout FlowLayout1 = new FlowLayout(); public MyApplet() { try { jbInit(); } catch(Exception e) { } } public static void main(String[] args) { MyApplet myApplet1 = new MyApplet(); } private void jbInit() throws Exception { setLayout(gridLayout2); panel1.setLayout(gridLayout1); checkbox1.setLabel("Флажок 1"); checkbox2.setLabel("Флажок 2"); checkbox2.setState(true); // Состояние флажка - // включен gridLayout2.setRows(2); panel2.setLayout(FlowLayout1); // Добавление в группу трех кнопок: checkbox4.setCheckboxGroup(checkboxGroup1); checkbox4.setLabel("Радиокнопка 1"); checkbox4.setState(true); // Состояние радиокнопки - // включена checkbox5.setCheckboxGroup(checkboxGroup1); checkbox5.setLabel("Радиокнопка 2"); checkbox6.setCheckboxGroup(checkboxGroup1); checkbox6.setLabel("Радиокнопка 3"); // Добавление кнопок в контейнеры - панели this.add(panel1, null); panel1.add(checkbox1, null); panel1.add(checkbox2, null); this.add(panel2, null); panel2.add(checkbox4, null); panel2.add(checkbox5, null); panel2.add(checkbox6, null); } }


    Листинг 27.2.

    Классы кнопок пакета javax. swing наследуются от класса AbstractButton. Этот класс предоставляет ряд общих методов, включая следующие:

  • doClick - выполнение щелчка мыши на кнопке программным способом;
  • getText- возвращает метку кнопки;
  • setText - устанавливает метку кнопки;
  • isSelected - определяет состояние кнопки и возвращает true, если переключаемая кнопка находится в состоянии "включена";
  • setSelected - устанавливает состояние кнопки;
  • setMargin - устанавливает отступы между рамкой кнопки и меткой;
  • setIcon - определяет пиктограмму, используемую по умолчанию. Эта пиктограмма используется для состояния кнопки "нажатая" или "недоступная" в том случае, если для этих состояний не указана иная пиктограмма;
  • setPressedIcon- определяет пиктограмму для нажатого ("pressed") состояния кнопки;
  • setSelectedIcon - устанавливает пиктограмму для выделенного ("selected") состояния кнопки;
  • setRolloverIcon - устанавливает пиктограмму для нажатого ("rollover") состояния кнопки (одновременно могут быть нажаты несколько кнопок);
  • setDisabledIcon- устанавливает пиктограмму для недоступного состояния кнопки.

    Например:

    ImageIcon ImageIcon1= new ImageIcon("myicon.gif"); jButton1.setDisabledIcon(ImageIcon1);

  • setDisabledSelectedIcon - устанавливает пиктограмму недоступного для выделения состояния кнопки;
  • setVerticalAlignment - определяет выравнивание по вертикали для пиктограммы и метки, которое может указываться следующими значениями:
  • SwingConstants.CENTER (по умолчанию);
  • SwingConstants.TOP;
  • - SwingConstants.BOTTOM;


  • setHorizontalAlignment - определяет выравнивание по горизонтали для пиктограммы и метки, которое может указываться следующими значениями:
  • SwingConstants.RIGHT (по умолчанию);
  • SwingConstants.LEFT;
  • SwingConstants.CENTER;
  • SwingConstants.LEADING;
  • SwingConstants.TRAILING;
  • setVerticalTextPosition - определяет позицию текста по вертикали относительно пиктограммы, которая может указываться следующими значениями:
  • SwingConstants.CENTER (по умолчанию);
  • SwingConstants.TOP;
  • SwingConstants.BOTTOM;
  • setHorizontalTextPosition - определяет позицию текста по горизонтали относительно пиктограммы, которая может указываться следующими значениями:
  • SwingConstants.RIGHT (по умолчанию);
  • SwingConstants.LEFT;
  • SwingConstants.CENTER;
  • SwingConstants.LEADING;
  • SwingConstants.TRAILING.
  • setActionCommand - задает команду действия для кнопки;
  • getActionCommand - возвращает строку, которая содержит команду действия, установленную для данной кнопки;
  • setMnemonic - определяет код символа, используемого как ключ-акселератор (ALT+данный символ).



  • Например:

    jButton1.setMnemonic(KeyEvent.VK_A);

    Для того чтобы определить в методе обработки события itemStateChanged(ItemEvent e), какой кнопкой было инициировано данное событие, следует использовать метод getItemSelectable.

    Для того чтобы определить, является ли кнопка, инициировавшая событие, выделенной (находящейся в состоянии "включена" или "нажата"), следует использовать метод getStateChange.

    Например:

    if (e.getItemSelectable() == jCheckBox1 && e.getStateChange()==e.SELECTED) { }

    Класс JToggleButton предназначен для создания кнопок, имеющих два состояния - "нажата" и "не нажата". Компонент JToggleButton может находится в зафиксированном нажатом состоянии (быть выделенным).

    Этот класс является непосредственным суперклассом для классов JCheckbox и JRadioButton.

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

    Например:

    jToggleButton1.setSelected(true);

    Кнопки JToggleButton могут быть объединены в группу. Такую группу следует предварительно создать, используя компонент типа javax.swing.ButtonGroup. Только одна из кнопок группы может одновременно иметь нажатое состояние.

    Панели

    Java-приложение создается как иерархия вложенных компонентов. Наверху этой иерархии могут находится компоненты классов Frame, JFrame, Applet или JApplet.
    Классы панелей используются как контейнеры для размещения других компонентов, в числе которых могут быть и сами панели. Пакет оконного интерфейса java.awt содержит один класс панели - Panel. Для добавления компонентов на панель класса Panel следует выполнить метод add, квалифицировав его именем панели.
    Пакет облегченных swing-компонентов предоставляет несколько классов панелей, включая следующие классы:
  • JRootPane
  • JPanel
  • JTabbedPane
  • JScrollPane
  • JSplitPane
  • JOptionPane
  • JToolbar.

  • При использовании менеджеров компоновки с панелями из пакета java.swing для получения ссылки на панель следует использовать метод getLayout.
    Например:
    ((CardLayout)jPanel1.getLayout()).next(jPanel1);
    Пакет javax.swing содержит интерфейс RootPaneContainer, реализуемый классами JApplet, JFrame, JInternalFrame, JWindow и JDialog.
    При добавлении компонентов в контейнер, использующий интерфейс RootPaneContainer , метод add надо квалифицировать следующим образом:
    frame.getContentPane().add(child).
    Класс JRootPane используется всеми панелями пакета javax.swing. Он позволяет размещать содержимое панели на нескольких уровнях. JRootPane представояет четыре уровня:
  • ContentPane - используется для отображения компонентов.
  • MenuBar - необязательный уровень, на котором можно размещать компоненты меню.
  • LayeredPane - используется для управления contentPane и menuBar.
  • GlassPane - самый ближайший к пользователю уровень. По умолчанию он невидим. glassPane, как правило, используется для отображения графики или каких-либо всплывающих компонентов. Компоненты этого уровня перекрывают компоненты, расположенные на более "низких" уровнях.

  • Уровень contentPane должен быть родительским для размещения любого компонента. Для доступа к данному уровню используется метод getContentPane().
    Уровень glassPane является самым верхним. Для доступа к данному уровню применяется метод getGlassPane().
    Чтобы в приложении можно было использовать уровень glassPane, для него следует вызвать метод setGlassPane().

    Например:

    panel1.getContentPane().add(button1);

    Компонент JTabbedPane реализует набор страниц, переключаемых по щелчку пользователя на вкладках. Вкладки добавляются методами addTab и insertTab. Вкладки нумеруются, начиная с 0.

    Если количество вкладок равно нулю, то индекс текущей вкладки равен -1.

    На рис. 27.5 показан внешний вид окна, содержащего панель вкладок класса JTabbedPane.

    Панели
    Рис. 27.5.  Окно с компонентом JTabbedPane

    Класс javax.swing.JScrollPane реализует компонент "прокручиваемая область".

    Панель JScrollPane состоит из:

  • области просмотра ( viewport) типа JViewport. Для добавления рамки вокруг области просмотра следует использовать метод setViewportBorder, а для добавления рамки вокруг всей прокручиваемой области - метод setBorder.;
  • вертикальной и горизонтальной области прокрутки типа JScrollBar (необязательная область);
  • области заголовков строк и области заголовкоd столбцов (необязательная область). Эти области реализуются как объекты типа JViewport, для которых вызваны методы setRowHeaderView и setColumnHeaderView;
  • четырех угловых областей. По умолчанию угловые области не содерджaт компонентов. Для того чтобы разместить в угловой области компонент, следует использовать метод setCorner.


  • Чтобы изменить свойство области просмотра, ее следует получить, вызвав метод getViewport. Например, для задания цвета фона нужно записать:

    scrollPane.getViewport().setBackground(Color.red).

    На рис. 27.6 показано расположение основных частей прокручиваемой области JScrollPane.

    Панели
    Рис. 27.6.  Окно с компонентом JTabbedPane

    Контейнером для разделяемых панелей служит компонент JSplitPane. Разделяемые плавающие панели имеют одну общую сторону - по вертикали или по горизонтали.

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

    import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Frame1 extends JPanel { JSplitPane jSplitPane1 = new JSplitPane(); // Класс // разделяемых панелей JScrollPane jScrollPane1 = new JScrollPane(); JScrollPane jScrollPane2 = new JScrollPane(); JTextPane jTextPane1 = new JTextPane(); JTextPane jTextPane2 = new JTextPane(); public Frame1() { try { jbInit(); } catch(Exception e) { } } public static void main(String s[]) { JFrame frame = new JFrame("Панели"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setContentPane(new Frame1()); frame.pack(); frame.setVisible(true); } private void jbInit() throws Exception { // Определение ориентации разделяемых панелей jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); // Размещение левого и правого компонента // на разделяемой панели jSplitPane1.setLeftComponent(jScrollPane1); jSplitPane1.setRightComponent(jScrollPane2); // Отображение кнопок сворачивания и разворачивания // сторон разделяемой панели jSplitPane1.setOneTouchExpandable(true); // Задание размера панелей jScrollPane1.setPreferredSize(new Dimension(300, 60)); jScrollPane2.setPreferredSize(new Dimension(300, 60)); // Добавление разделяемой панели к окну формы this.add(jSplitPane1, null); // Добавление компонентов в контейнеры // типа JScrollPane jScrollPane1.getViewport().add(jTextPane1, null); jScrollPane2.getViewport().add(jTextPane2, null); } }

    Листинг 27.1.

    Применение компоновок

    При проектировании интерфейса пользователя с использованием языка Java компоненты размещаются в контейнерах. Самым простым примером контейнера может служить окно формы (класс Frame). В общем случае любой класс, наследуемый от класса контейнера java.awt.Container, является контейнером.
    В языке Java для "плавающего" размещения компонентов, зависящего от размеров окна и размеров самих компонентов, введены классы компоновок.
    Компоновка определяет порядок расположения компонентов на экране. Перед отображением объектов-контейнеров, содержащих другие компоненты, вызывается менеджер компоновки. Он располагает компоненты на экране в соответствующем порядке. Используемый менеджер компоновки указывается вызовом метода setLayout. Если менеджер компоновки не указан явно, то выбирается тот, что используется по умолчанию для данного класса контейнера.
    Для того чтобы отключить использование менеджеров компоновки и перейти к явному указанию координат, следует вызвать метод setLayuot(null).
    Пакеты java.awt и javax.swing предоставляют следующие классы менеджеров компоновки:
  • java.awt.FlowLayout - создает последовательное размещение объектов с указанным выравниванием и заданными между этими объектами интервалами.
  • java.awt.GridLayout - создает табличное размещение объектов с заданным числом строк и столбцов, объекты располагаются последовательно слева направо.
  • java.awt.GridBagLayout - создает гибкое табличное размещение объектов, позволяя размещать один компонент в нескольких ячейках.
  • java.awt.BorderLayout - создает размещение объектов по краю контейнера (вверху, внизу, слева, справа и в центре).
  • java.awt.CardLayout - создает компоновку контейнера, отображая одновременно только один компонент. Как правило, в качестве компонент для данного менеджера компоновки выступают панели.
  • javax.swing.ScrollPaneLayout - позволяет размещать компоненты на девяти различных областях; является компоновкой по умолчанию для класса ScrollPane.
  • javax.swing.ViewportLayout - является компоновкой по умолчанию для класса Jviewport.
  • javax.swing.BoxLayout - является компоновкой по умолчанию для класса Box.
  • javax.swing.OverlayLayout - позволяет размещать компоненты один над другим.


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

    Например:

    GridBagLayout gridBagLayout1 = new GridBagLayout(); this.setLayout(gridBagLayout1); Button button1 = new Button(); button1.setLabel("Кнопка 1"); this.add(button1, new GridBagConstraints(0, 0, 3, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 315, 0));

    Метод setLayout следует квалифицировать именем контейнера, для которого устанавливается компоновка. Для класса контейнера, в котором выполняется данный метод, можно использовать ссылку this. В случае предварительного создания объекта "менеджер компоновки", его следует указать как параметр метода setLayout. В противном случае в качестве параметра метода setLayout следует указать оператор создания анонимного объекта "менеджер компоновки".

    Например:

    this.setLayout(gridLayout1); // или this.setLayout(new GridLayout());

    При использовании панели типа Panel методы объекта "менеджер компоновки" вызываются стандартным образом имя_объекта_менеджер_компоновки.имя_метода.

    Например:

    cardLayout1.show(Panel1,"Panel0");.

    При использовании панели типа JPanel методы объекта "менеджер компоновки" вызываются с использованием метода getLayout.

    Например:

    ((CardLayout)jPanel2.getLayout()).show(jPanel2,"jPanel0");

    Списки

    Списки позволяют отображать группу элементов в один столбец, предоставляя пользователю возможность выбора элемента.
    Библиотека JDK содержит ряд классов списков, включая следующие:
  • java.awt.List - список.
  • java.awt.Choice - ниспадающий список.
  • javax.swing.JList - список.
  • javax.swing.JComboBox - ниспадающий список.

  • При выделении элемента в списке или в ниспадающем списке (или отмене выделения) инициируется событие itemStateChanged. В метод обработки этого события передается объект типа ItemEvent. Используя свойство SELECTED для объекта типа ItemEvent, можно определить, выделен ли элемент списка. Интерфейс ItemListener описывает метод обработки события itemStateChanged.
    При двойном щелчке мышью на элементе списка (или нажатии клавиши Enter при выделенном элементе списка) для компонента типа List, JList или JComboBox инициируется событие actionPerformed. В метод обработки этого события передается объект типа ActionEvent. Интерфейс ActionListener описывает метод обработки события actionPerformed.
    Заполнение списков можно выполнять в обработчике события фрейма windowOpened. Добавление элементов в список List и Choice выполняется методом add.
    Например:
    List list1 = new List(4, false); // Создание списка // с 4 видимыми строками и с запретом множественного выбора list1.add("Строка 1"); // Добавление элементов в список list1.add("Строка 2"); list1.add("Строка 3"); list1.add("Строка 4"); list1.add("Строка 5"); list1.add("Строка 6"); add(list1); // Добавление списка в текущий контейнер
    Список JList позволяет выделять один или несколько элементов. Содержание списка представляется моделью ListModel. Доступ к элементам списка реализуется с использованием модели. Для заполнения списка используется метод setListData.
    Список JList непосредственно не поддерживает прокрутку списка. Реализовать скроллинг можно двумя способами:
  • Поместить список в контейнер типа JScrollPane. Например:
    JScrollPane scrollPane = new JScrollPane(jList1);
  • Установить для объекта типа JScrollPane на уровне Viewport (getViewport) в качестве компонента области просмотра (setView) объект типа JList. Например:
    JScrollPane scrollPane = new JScrollPane(); scrollPane.getViewport().(jList1);

  • Например:
    String[] data = {"один", "два", "три"}; // Массив строк JList jList1 = new JList(data); // Создание списка, // содержащего массив строк // Доступ к элементам списка через модель for(int i = 0; i Листинг 27.3.
    Списки

    Текстовые компоненты

    Текстовые компоненты предназначаются для ввода и отображения строк.
    Библиотека JDK предоставляет следующие классы текстовых компонентов:
  • java.awt.TextArea - текстовая область.
  • java.awt.TextField - текстовое поле, называемое также полем ввода.
  • javax.swing.JTextField - текстовое поле.
  • javax.swing.JPasswordField - текстовое поле, предназначаемое для ввода пароля.
  • javax.swing.JTextArea - текстовая область.
  • javax.swing.JEditorPane - панель редактора, позволяющая отображать как текстовые, так и графические данные, а также применять различное форматирование текста.
  • javax.swing.JTextPane - текстовая панель, позволяющая отображать содержимое с использованием различных шрифтов.

  • Все текстовые компоненты пакета java.awt наследуются от класса TextComponent.
    Все текстовые компоненты пакета javax.swing наследуются от класса JTextComponent.
    Для отображения текста, который может быть изменен только программным путем, служат компоненты .Label из пакета java.awt и JLabel из пакета javax.swing.
    Компонент JLabel также можно использовать и для отображения рисунков.
    Большинство названий методов, предоставляемых классами TextComponent и JTextComponent для работы с текстом, совпадают. Так, для того чтобы получить строку, которая содержит весь текст, расположенный в текстовом компоненте, можно использовать метод getText, а для получения позиции ввода - метод getCaretPosition; для определения, можно ли редактировать текст, - метод isEditable, для выделения текста в указанном диапазоне - метод select, а для выделения всего текста - метод selectAll.
    При каждом изменении значения текстового компонента, включая ввод каждого символа, происходит событие textValueChanged. При нажатии на клавишу Enter для текстового поля инициируется событие actionPerformed. Но при перемещении фокуса ввода событие actionPerformed не происходит.
    для ввода и редактирования одной строки текста. Этот класс предоставляет ряд методов, включая следующие:
  • AddActionListener - регистрирует блок прослушивания для обработки события действия компонента "текстовое поле".
  • EchoCharIsSet - возвращает значение true в том случае, если ввод в данное текстовое поле отображается некоторым эхо-символом, скрывающим действительное значение поля.
  • GetColumns - возвращает размер данного текстового поля (количество символов).
  • GetEchoChar - возвращает эхо-символ для данного текстового поля.
  • SetEchoCharacter - устанавливает значение эхо-символа для данного текстового поля.
    Любой вводимый пользователем символ будет экранирован данным эхо-символом.
  • SetColumns - устанавливает размер текстового поля в символах.
  • SetText - определяет новое значение текстового поля.


  • Хотя компоненты пакета javax.swing и называются облегченными, но они предоставляют значительно большие возможности, чем традиционные текстовые компоненты пакета java.awt.

    Управление текстом, отображаемым в текстовом компоненте, определяется интерфейсом Document. Этот интерфейс предназначен для определения методов работы с текстом. Интерфейс Documentреализован классом AbstractDocument.

    Текст в компоненте типа JTextComponent представляется ассоциируемой с ним текстовой моделью, определяющей как содержание, так и стиль.

    Фактически, текстовый компонент предоставляет доступ к:

  • модели, реализуемой на основе интерфейса Document и представляющей собой содержание документа;
  • области просмотра текстового компонента;
  • набору команд редактирования, предусмотренного для текстового компонента;
  • таблице ключей акселераторов, связанных с таблицей именованных действий.


  • Класс DefaultEditorKit и StyledEditorKit описывают набор именованных действий, которые можно использовать для создания на основе текстового компонента редактора текста.

    В классе DefaultEditorKit определен набор предоставляемых текстовому компоненту действий, таких как перемещение курсора, выделение или вставка текста.

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

    menu.add(new StyledEditorKit.FontSizeAction ( "Имя пункта меню", 14));

    Константы класса DefaultEditorKit описывают набор именованных действий, включая следующие:

  • BackwardAction - перемещение позиции ввода на одну позицию назад.
  • BeepAction - подача звукового сигнала.
  • BeginAction - перемещение позиции ввода на начало документа.
  • BeginParagraphAction - перемещение позиции ввода в начало абзаца.
  • BeginLineAction - перемещение позиции ввода в начало строки.
  • BeginWordAction - перемещение позиции ввода на начало текущего слова.
  • CutAction - вырезание выделенного диапазона текста и помещение его в буфер обмена.
  • CopyAction - копирование выделенного диапазона текста в буфер обмена.
  • DeleteNextCharAction - удаление следующего символа.
  • DownAction- перемещение позиции ввода на один ряд вниз.
  • DeletePrevCharAction - удаление предыдущего символа.
  • EndAction - перемещение позиции ввода в конец документа.
  • EndLineAction - перемещение позиции ввода в конец строки.
  • EndParagraphAction - перемещение позиции ввода в конец абзаца.
  • EndWordAction - перемещение позиции ввода на конец текущего слова.
  • ForwardAction - перемещение позиции ввода на один символ вперед.
  • InsertBreakAction - вставка в документ символа конца абзаца.
  • InsertTabAction - вставка символа табуляции.
  • NextWordAction - перемещение позиции ввода на начало следующего слова.
  • PageDownAction - перемещение позиции ввода на одну страницу вниз.
  • PageUpAction - перемещение позиции ввода на одну страницу вверх.
  • PasteAction - вставка содержимого буфера обмена вместо выделенного диапазона текста или перед текущей позицией ввода.
  • PreviousWordAction - перемещение позиции ввода на начало предыдущего слова.
  • ReadOnlyAction - перевод редактора в режим "только чтение".
  • SelectAllAction - выделение всего документа.
  • SelectionBackwardAction - расширение области выделения на одну позицию назад (влево).
  • SelectionBeginAction - расширение области выделения до начала документа.
  • SelectionBeginLineAction- расширение области выделения до начала текущей строки.
  • SelectionBeginParagraphAction - расширение области выделения до начала текущего абзаца.
  • SelectionBeginWordAction - расширение области выделения до начала текущего слова.
  • SelectionDownAction - расширение области выделения на одну позицию вниз.
  • SelectionEndAction - расширение области выделения до конца документа.
  • SelectionEndLineAction - расширение области выделения до конца строки.
  • SelectionEndParagraphAction- расширение области выделения до конца абзаца.
  • SelectionEndWordAction - расширение области выделения до конца текущего слова.
  • SelectionForwardAction - расширение области выделения на один символ вперед (вправо).
  • SelectionNextWordAction - расширение области выделения до начала следующего слова.
  • SelectionPreviousWordAction - расширение области выделения до начала предыдущего слова.
  • SelectionUpAction - расширение области выделения на одну позицию вверх.
  • SelectLineAction - выделение строки, в которой расположена позиция ввода.
  • SelectParagraphAction - выделение абзаца, в котором расположена позиция ввода.
  • SelectWordAction - выделение слова, в котором расположена позиция ввода.
  • UpAction - перемещение позиции ввода на одну позицию вниз.
  • WritableAction - перевод редактора в режим редактирования текста.



  • Для того чтобы добавить в документ строку в отформатированном виде, можно использовать метод insertS класса DefaultStyledDocument. Этот класс является подклассом класса AbstractDocumentи реализует интерфейсы Document и StyledDocument.

    Интерфейс StyledDocument определяет методы для работы со стилем документа. Так, для назначения диапазону текста набора атрибутов стиля можно использовать метод setCharacter-Attributes, а для определения используемого стиля или шрифра - методы getStyle и getFont.

    Атрибуты стиля определяются интерфейсом AttributeSet. Этот интерфейс реализован классом SimpleAttributeSet.

    Для создания набора атрибутов стиля следует создать переменную типа SimpleAttributeSet и установить атрибуты стиля, используя методы класса

    Например:

    SimpleAttributeSet attrSt = new SimpleAttributeSet(); StyleConstants.setBold(attrSt, true); StyleConstants.setFontSize(attrSt, 12); StyleConstants.setForeground(attrSt, Color.red);

    При добавлении строки в текстовый документ вызовом метода insertString класса Default-StyledDocument один из параметров ссылается на набор аттрибутов.

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

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

  • Создать объект класса Keymap для компонента класса JTextPane.

    Например:

    JTextPane textPane; .... Keymap keymap = textPane.addKeymap("MyKeymap", textPane.getKeymap());

  • Создать объект класса Action и установить для него действие, описанное в классе DefaultEditorKit.

    Например:

    Action action = getActionByName(DefaultEditorKit.downAction);
  • Создать объект класса KeyStroke и установить для него значение ключа акселератора.

    Например:

    KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_N, Event.CTRL_MASK);

  • Установить связь между созданным действием и ключем акселератором.


    Например:

    keymap.addActionForKeyStroke(key, action);


  • Класс StyleConstants предоставляет набор методов, позволяющих определять или устанавливать значения для атрибутов форматирования.

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

  • SimpleAttributeSet .
  • AttributeSet .
  • MutableAttributeSet .


  • Например:

    ...SimpleAttributeSet[] attrs = new SimpleAttributeSet[stringForPane.length +1]; // Создание набора атрибутов: attrs[0] = new SimpleAttributeSet(); StyleConstants.setFontFamily(attrs[0], "SansSerif"); // Установка значения атрибута StyleConstants.setFontSize(attrs[0], 12); attrs[1] = new SimpleAttributeSet(attrs[0]); StyleConstants.setFontSize(attrs[1], 14); StyleConstants.setBold(attrs[1], true); // Добавление строки в документ с заданным набором // атрибутов (defaultStyleDocument1 переменная // класса, наследуемого от DefaultStyleDocument) defaultStyleDocument1.insertString( defaultStyleDocument1.length, string1, attrs[1]);

    Введение в программирование

    CGI и ISAPI приложения

    Данные, отображаемые web-браузером, представляют собой HTML-страницу.
    По HTTP-запросу web-браузер посылает на web-сервер информацию, содержащую URL-адрес документа, тип запроса и значения параметров. URL-адрес может указывать как простую HTML-страницу и приложение, выполняемое на web-сервере. Такое приложение иногда называется серверным приложением.
    К серверным приложениям относятся CGI-приложения и ISAPI-приложения.
    В отличии от CGI-приложений, выполняемых в отдельном процессе, ISAPI-приложения реализуются как DLL-библиотеки.
    Результатом выполнения CGI или ISAPI-приложения чаще всего является динамически сформированная HTML-страница.

    только на тот случай, если

    // Заголовочный файл MyISAPI_1.h #pragma once #include "resource.h" class CMyISAPI_1Extension : public CHttpServer { public: CMyISAPI_1Extension(); // Конструктор ~CMyISAPI_1Extension(); public: virtual BOOL GetExtensionVersion(HSE_VERSION_INFO* pVer); virtual BOOL TerminateExtension(DWORD dwFlags); void Default(CHttpServerContext* pCtxt); DECLARE_PARSE_MAP() }; // Файл реализации MyISAPI_1.cpp #include "stdafx.h" #include "MyISAPI_1.h" CWinApp theApp; // Объект "приложение" BEGIN_PARSE_MAP(CMyISAPI_1Extension, CHttpServer) // Таблица // обработки команды // TODO: место для определения ON_PARSE_COMMAND() и // ON_PARSE_COMMAND_PARAMS() ON_PARSE_COMMAND(Default, CMyISAPI_1Extension, ITS_EMPTY) DEFAULT_PARSE_COMMAND(Default, CMyISAPI_1Extension) END_PARSE_MAP(CMyISAPI_1Extension) CMyISAPI_1Extension theExtension; // Только один объект //ISAPI-расширение класса, // наследуемого от CHttpServer CMyISAPI_1Extension::CMyISAPI_1Extension(){ } // Конструктор CMyISAPI_1Extension::~CMyISAPI_1Extension() { } BOOL CMyISAPI_1Extension::GetExtensionVersion(HSE_VERSION_INFO* pVer) { // Вызов метода базового класса CHttpServer::GetExtensionVersion(pVer); // Загрузка строки описания TCHAR sz[HSE_MAX_EXT_DLL_NAME_LEN+1]; ISAPIVERIFY(::LoadString(AfxGetResourceHandle(), // Макро - если IDS_SERVER, sz, HSE_MAX_EXT_DLL_NAME_LEN)); // 0,то завершение _tcscpy(pVer->lpszExtensionDesc, sz); return TRUE; } BOOL CMyISAPI_1Extension::TerminateExtension(DWORD dwFlags) { // Метод класса CHttpServer - позволяет выполнить завершение // потоков и работы ISAPI-расширения return TRUE; } // CMyISAPI_1Extension : методы обработчики // Код формируемой HTML-страницы записывается методом Default // в поток вывода void CMyISAPI_1Extension::Default(CHttpServerContext* pCtxt) { StartContent(pCtxt); // Начало HTML-страницы WriteTitle(pCtxt); // Формирование значения тега TITLE // _T - для Unocode конвертируется в L *pCtxt << _T(" HTML-page from "); // Первая строка //HTML-страницы *pCtxt << _T("ISAPI-application "); // Формирование строки HTML-документа для отображения формы *pCtxt << _T("
    "); EndContent(pCtxt); // Завершение HTML-страницы } // Следующие строки вставляются мастером // ISAPI Extension Wizard // только на тот случай, если ISAPI-расширение не будет // использовать MFC-бибиотеку. // В противном случае эти строки можно удалить /**** static HINSTANCE g_hInstance; HINSTANCE AFXISAPI AfxGetResourceHandle() { return g_hInstance;} BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason, // Точка LPVOID lpReserved) // входа в DLL-модуль { if (ulReason == DLL_PROCESS_ATTACH) { g_hInstance = hInst; } return TRUE; } ****/

    Листинг 28.1.
    Закрыть окно





    // Заголовочный файл MyISAPI_1.h

    #pragma once

    #include "resource.h"

    class CMyISAPI_1Extension : public CHttpServer

    {

    public:

    CMyISAPI_1Extension(); // Конструктор

    ~CMyISAPI_1Extension();

    public:

    virtual BOOL GetExtensionVersion(HSE_VERSION_INFO* pVer);

    virtual BOOL TerminateExtension(DWORD dwFlags);

    void Default(CHttpServerContext* pCtxt);

    DECLARE_PARSE_MAP()

    };

    // Файл реализации MyISAPI_1.cpp

    #include "stdafx.h"

    #include "MyISAPI_1.h"

    CWinApp theApp; // Объект "приложение"

    BEGIN_PARSE_MAP(CMyISAPI_1Extension, CHttpServer) // Таблица

    // обработки команды

    // TODO: место для определения ON_PARSE_COMMAND() и

    // ON_PARSE_COMMAND_PARAMS()

    ON_PARSE_COMMAND(Default, CMyISAPI_1Extension, ITS_EMPTY)

    DEFAULT_PARSE_COMMAND(Default, CMyISAPI_1Extension)

    END_PARSE_MAP(CMyISAPI_1Extension)

    CMyISAPI_1Extension theExtension; // Только один объект

    //ISAPI-расширение класса,

    // наследуемого от CHttpServer

    CMyISAPI_1Extension::CMyISAPI_1Extension(){ } // Конструктор

    CMyISAPI_1Extension::~CMyISAPI_1Extension() { }

    BOOL CMyISAPI_1Extension::GetExtensionVersion(HSE_VERSION_INFO* pVer)

    { // Вызов метода базового класса

    CHttpServer::GetExtensionVersion(pVer);

    // Загрузка строки описания

    TCHAR sz[HSE_MAX_EXT_DLL_NAME_LEN+1];

    ISAPIVERIFY(::LoadString(AfxGetResourceHandle(), // Макро - если

    IDS_SERVER, sz, HSE_MAX_EXT_DLL_NAME_LEN)); // 0,то завершение

    _tcscpy(pVer->lpszExtensionDesc, sz);

    return TRUE;

    }

    BOOL CMyISAPI_1Extension::TerminateExtension(DWORD dwFlags)

    { // Метод класса CHttpServer - позволяет выполнить завершение

    // потоков и работы ISAPI-расширения

    return TRUE;

    }

    // CMyISAPI_1Extension : методы обработчики

    // Код формируемой HTML- страницы записывается методом Default

    // в поток вывода

    void CMyISAPI_1Extension::Default(CHttpServerContext* pCtxt)

    {

    StartContent(pCtxt); // Начало HTML-страницы

    WriteTitle(pCtxt); // Формирование значения тега TITLE

    // _T - для Unocode конвертируется в L

    указатель на строку, значение типа

    BEGIN_PARSE_MAP(CDerivedClass, CHttpServer) DEFAULT_PARSE_COMMAND(Myfunc, CDerivedClass) // Для запроса типа // http://LOCALSERVER/MyISAPI_1.dll?Myfunc&string1&135 ON_PARSE_COMMAND(Myfunc, // Имя функции CDerivedClass, // Имя класса ITS_PSTR ITS_I2) // Список из двух параметров: // указатель на строку, значение типа short ON_PARSE_COMMAND_PARAMS("string integer=42")

    // Для запроса с тремя параметрами ON_PARSE_COMMAND(Myfunc2, CDerivedClass, ITS_PSTR ITS_I2 ITS_PSTR) ON_PARSE_COMMAND_PARAMS("string integer string2='Default value'") DEFAULT_PARSE_COMMAND(Myfunc3, CDerivedClass) ON_PARSE_COMMAND(Myfunc3, CDerivedClass, ITS_RAW) // Различное число параметров END_PARSE_MAP(CDerivedClass)

    // Функции, выполняемые для обработки команд void Myfunc(CHttpServerContext* pCtxt, LPTSTR pszName, int nNumber) { } // Первый параметр стандартен для всех функций, // обрабатывающих команды, тип второго и третьего // параметра был указан в макросе ON_PARSE_COMMAND void Myfunc2(CHttpServerContext* pCtxt, LPTSTR pszName, int nNumber, LPTSTR pszTitle) { } void CDerivedClass::Myfunc3( // Используется тип параметров // ITS_RAW CHttpServerContext* pCtxt, void* pVoid, // pVoid - указатель на передаваемые данные DWORD dwBytes) // dwBytes - количество переданных байтов данных { }

    Листинг 28.2.
    Закрыть окно





    BEGIN_PARSE_MAP(CDerivedClass, CHttpServer)

    DEFAULT_PARSE_COMMAND(Myfunc, CDerivedClass)

    // Для запроса типа

    // http://LOCALSERVER/MyISAPI_1.dll?Myfunc&string1&135

    ON_PARSE_COMMAND(Myfunc, // Имя функции

    CDerivedClass, // Имя класса

    ITS_PSTR ITS_I2) // Список из двух параметров:

    // указатель на строку, значение типа short

    ON_PARSE_COMMAND_PARAMS("string integer=42")

    // Для запроса с тремя параметрами

    ON_PARSE_COMMAND(Myfunc2,

    CDerivedClass,

    ITS_PSTR ITS_I2 ITS_PSTR)

    ON_PARSE_COMMAND_PARAMS("string integer string2='Default value'")

    DEFAULT_PARSE_COMMAND(Myfunc3, CDerivedClass)

    ON_PARSE_COMMAND(Myfunc3, CDerivedClass,

    ITS_RAW) // Различное число параметров

    END_PARSE_MAP(CDerivedClass)

    // Функции, выполняемые для обработки команд

    void Myfunc(CHttpServerContext* pCtxt, LPTSTR pszName, int nNumber)

    { } // Первый параметр стандартен для всех функций,

    // обрабатывающих команды, тип второго и третьего

    // параметра был указан в макросе ON_PARSE_COMMAND

    void Myfunc2(CHttpServerContext* pCtxt, LPTSTR pszName,

    int nNumber, LPTSTR pszTitle)

    { }

    void CDerivedClass::Myfunc3( // Используется тип параметров

    // ITS_RAW

    CHttpServerContext* pCtxt,

    void* pVoid, // pVoid - указатель на передаваемые данные

    DWORD dwBytes) // dwBytes - количество переданных байтов данных

    { }

    cs using System; using

    // Default.aspx. cs using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls;

    public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } } // Default.aspx <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>



    Untitled Page
     


    // StyleSheet.css - файл таблицы стилей body { font-size: 18pt; color: blue; } .Cl1 { font-size: 24pt; color: red; }
    Листинг 28.3.
    Закрыть окно





    // Default.aspx.cs

    using System;

    using System.Data;

    using System.Configuration;

    using System.Web;

    using System.Web.Security;

    using System.Web.UI;

    using System.Web.UI.WebControls;

    using System.Web.UI.WebControls.WebParts;

    using System.Web.UI.HtmlControls;

    public partial class _Default : System.Web.UI.Page

    { protected void Page_Load(object sender, EventArgs e)

    { }

    }

    // Default.aspx

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

    HTTP-запросы

    НТТР-запрос формируется в соответствии с протоколом HTTP (HyperText Transfer Protocol). В HTTP-запросе указывается GET- или POST-метод передачи данных. При вводе URL-адреса в поле адреса web-браузера или выполнении формы (пользователь щелкнул по кнопке типа SUBMIT) формируется HTTP-запрос. Если форма содержала данные, то они будут добавлены в конец строки с URL-адресом (при использовании метода GET). Соответственно, такой способ накладывает ограничение на размер передаваемых параметров. Если при выполнении формы атрибут METOD установлен равным POST, то используется POST-метод, при котором сначала на сервер посылается строка POST-запроса и HTTP-заголовки запроса, а затем пустая строка и строка, содержащая передаваемые параметры.
    ISAPI-приложение может использоваться как для формирования динамической HTML-страницы, так и для обработки параметров, получаемых от формы.
    В строке адреса web-браузера может быть указан только непосредственно URL-адрес выполняемого серверного приложения. В этом случае для обработки такого запроса используется команда, определяемая макросом DEFAULT_PARSE_COMMAND.
    Если после URL-адреса за вопросительным знаком следует идентификатор команды, то для обработки данного HTTP-запроса следует использовать функцию, сопоставленную данной команде макросом ON_PARSE_COMMAND.
    Например, для обработки строки
    http://LOCALHOST/MyISAPI_1.dll?Myfunc?string1&123
    ISAPI-приложение будет вызывать функцию Myfunc и передавать ей в качестве параметров три значения: первым параметром всегда будет указатель на HTTP-контекст, а далее будут следовать параметры, указанные в HTTP-запросе. В данном примере это два параметра: string1 и 123. Между собой параметры разделяются символом &.

    Применение Cookies

    Cookies - это данные, сохраняемые на ПК клиента (web-браузера). Пользователь имеет возможность запретить сохранять Cookies на своем ПК. Если запись Cookies разрешена, то они записываются при каждом получении ответа от web -сервера и передаются обратно с каждым следующим HTTP-запросом.
    Для задания Cookies следует в обработчике события действия ввести следующий код:
    with Response.Cookies.Add do Name:='Cook1''; // Имя данных Value:='ValueCook1''; // Значение end;
    Для запроса Cookies следует в обработчике события действия ввести следующий код:
    s1:=Request.CookieFields.ValueFromIndex[0]; // Request.CookieFields.Count - число полей в Cookies

    Разбор параметров

    Для доступа к значению формы из GET-запроса используется метод QueryFields объекта типа TWebRequest.
    Например:
    var1:=Request.QueryFields.Values["Имя_поля"]; var1:=Request.QueryFields.ValueFromIndex[0];
    Для доступа к значению формы из POST-запроса используется метод ContentFields объекта типа TWebRequest.
    Например:
    var1:=Request.ContentFields.Values["Имя_поля"]; var1:=Request.ContentFields.ValueFromIndex [0]
    Для доступа к параметрам самого запроса используется метод GetFieldByName:
    Например:
    Request.GetFieldByName('URL'); Request.GetFieldByName('METOD'); // Эквивалентно // выполнению Request.Metod;

    Разбор списка параметров

    Для запросов типа http://LOCALSERVER/MyISAPI_2.dll?Myfunc&s1= 10&s2=35&c1=y можно использовать макрос с типом параметров ITS_ARGLIST :
    ON_PARSE_COMMAND(Myfunc, CMyHttpServer, ITS_ARGLIST).
    Далее для разбора такого списка параметров используется класс CHttpArgList.
    Класс CHttpArgList представляет собой массив структур типа CHttpArg.
    При этом данные доступны через объект CHttpArg.
    Поле CHttpArg::m_pstrValue содержит значение параметра, а поле CHttpArg::m_pstrArg - имя параметра.
    Например:
    для строки http://localserver/my1.dll&Arg1=hockey&Arg2&Arg3=beer+nuts надо реализовать разбор параметров по следующей схеме.
    Разбор списка параметров

    Создание CGI-приложения

    Если WEB-броузер посылает в качестве запроса URL-адрес CGI-приложения, то web-сервер запускает это приложение и передает ему параметры запроса через стандартный ввод. Сформированная в результате выполнения CGI-приложения HTML-страница возвращается WEB-серверу через стандартный вывод.
    Для того, чтобы создать CGI-приложение, запускаемое на сервере, следует создать проект Web Server Application и в диалоге New Web Server Application (рис. 28.3) выбрать тип серверного приложения (например, CGI Stand-alone executable).
    Создание CGI-приложения
    Рис. 28.3.  Диалог New web Server Application
    В результате будет создан проект, содержащий главный файл приложения и модуль Unit1:
    {Главный файл приложения} program Project1; {$APPTYPE CONSOLE} uses WebBroker, CGIApp, Unit1 in 'Unit1.pas' {WebModule1: TWebModule}; {$R *.RES} begin Application.Initialize; Application.CreateForm(TWebModule1, WebModule1); Application.Run; end. {Модуль Unit1.pas} unit Unit1; interface uses SysUtils, Classes, HTTPApp; type TWebModule1 = class(TWebModule) private { Private declarations } public { Public declarations } end; var WebModule1: TWebModule1; implementation {$R *.DFM} end.
    Для того чтобы создать код, формирующий HTML-страницу, следует создать объект типа TWebActionItem (например, WebActionItem1), а далее создать для данного объекта обработчик события действия OnAction.
    При этом автоматически будет сформирован следующий код:
    procedure TWebModule1.WebModule1WebActionItem1Action( Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); begin end;
    Код HTML-страницы записывается в свойство Content объекта Response.
    Например:
    //1. Response.Content:='Результат выполнения '+ CGI-приложения
    ; // 2. var aPage : TStringList; i: integer; begin aPage:= TStringList.Create; aPage.Add('Method = ' +Request.Method + '
    '); aPage.Add('URL = ' + Request.URL+ '
    '); aPage.Add('User Agent = ' + Request.UserAgent+ '
    '); aPage.Add('Remote Address = ' + Request.RemoteAddr+ '
    '); aPage.Add('Remote Host = ' + request.RemoteHost+ '
    '); Response.Content := aPage.Text; aPage.Free;
    После размещения созданного CGI-приложения в каталог WEB-сервера, предназначенный для исполняемых файлов, web -браузер может формировать запрос, указывая URL-адрес данного CGI-приложения.

    Создание ISAPI-приложения

    Для того чтобы создать ISAPI-приложение, иногда также называемое ISAPI-расширением, следует:
  • создать новый проект;
  • в диалоге New Project выбрать шаблон создаваемого документа MFC ISAPI Extension Dll;
  • перейти на страницу Object Setting мастера ISAPI Extension Wizard и установить флажок Generate a server extension object. В результате выполненных действий мастер ISAPI Extension Wizard сформирует шаблон ISAPI-приложения. В заголовочном файле StdAfx.h, который добавляется в шаблон любого приложения, использующего MFC-библиотеку, указана строка #include - она выполняет подключение файла afxisapi.h, который объявляет следующие классы, поддерживающие работу с HTTP-запросами:

  • class ChtmlStream. class ChttpServerContext. class ChttpServer. class ChttpFilterContext. class ChttpFilter. class CHttpArgList.
    ISAPI-приложение создается как DLL-библиотека. Класс, выполняющий обработку HTTP-запроса и формирующий динамическую HTML-страницу, наследуется от класса CHttpServer.
    В следующем листинге приведен код заголовочного файла и файла реализации класса, наследуемого от CHttpServer. В автоматически сформированный код ISAPI-приложения внесены изменения, которые добавляют в создаваемую HTML-страницу две строки текста и форму, содержащую элемент управления.
    Листинг:
    // Заголовочный файл MyISAPI_1.h #pragma once #include "resource.h" class CMyISAPI_1Extension : public CHttpServer { public: CMyISAPI_1Extension(); // Конструктор ~CMyISAPI_1Extension(); public: virtual BOOL GetExtensionVersion(HSE_VERSION_INFO* pVer); virtual BOOL TerminateExtension(DWORD dwFlags); void Default(CHttpServerContext* pCtxt); DECLARE_PARSE_MAP() }; // Файл реализации MyISAPI_1.cpp #include "stdafx.h" #include "MyISAPI_1.h" CWinApp theApp; // Объект "приложение" BEGIN_PARSE_MAP(CMyISAPI_1Extension, CHttpServer) // Таблица // обработки команды // TODO: место для определения ON_PARSE_COMMAND() и // ON_PARSE_COMMAND_PARAMS() ON_PARSE_COMMAND(Default, CMyISAPI_1Extension, ITS_EMPTY) DEFAULT_PARSE_COMMAND(Default, CMyISAPI_1Extension) END_PARSE_MAP(CMyISAPI_1Extension) CMyISAPI_1Extension theExtension; // Только один объект //ISAPI-расширение класса, // наследуемого от CHttpServer CMyISAPI_1Extension::CMyISAPI_1Extension(){ } // Конструктор CMyISAPI_1Extension::~CMyISAPI_1Extension() { } BOOL CMyISAPI_1Extension::GetExtensionVersion(HSE_VERSION_INFO* pVer) { // Вызов метода базового класса CHttpServer::GetExtensionVersion(pVer); // Загрузка строки описания TCHAR sz[HSE_MAX_EXT_DLL_NAME_LEN+1]; ISAPIVERIFY(::LoadString(AfxGetResourceHandle(), // Макро - если IDS_SERVER, sz, HSE_MAX_EXT_DLL_NAME_LEN)); // 0,то завершение _tcscpy(pVer->lpszExtensionDesc, sz); return TRUE; } BOOL CMyISAPI_1Extension::TerminateExtension(DWORD dwFlags) { // Метод класса CHttpServer - позволяет выполнить завершение // потоков и работы ISAPI-расширения return TRUE; } // CMyISAPI_1Extension : методы обработчики // Код формируемой HTML-страницы записывается методом Default // в поток вывода void CMyISAPI_1Extension::Default(CHttpServerContext* pCtxt) { StartContent(pCtxt); // Начало HTML-страницы WriteTitle(pCtxt); // Формирование значения тега TITLE // _T - для Unocode конвертируется в L *pCtxt << _T(" HTML-page from "); // Первая строка //HTML-страницы *pCtxt << _T("ISAPI-application "); // Формирование строки HTML-документа для отображения формы *pCtxt << _T("
    "); EndContent(pCtxt); // Завершение HTML-страницы } // Следующие строки вставляются мастером // ISAPI Extension Wizard // только на тот случай, если ISAPI-расширение не будет // использовать MFC-бибиотеку. // В противном случае эти строки можно удалить /**** static HINSTANCE g_hInstance; HINSTANCE AFXISAPI AfxGetResourceHandle() { return g_hInstance;} BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason, // Точка LPVOID lpReserved) // входа в DLL-модуль { if (ulReason == DLL_PROCESS_ATTACH) { g_hInstance = hInst; } return TRUE; } ****/
    Листинг 28.1.
    Каждый запрос обрабатывается некоторой функцией. При вызове такой функции, в качестве параметра ей передается объект типа CHttpServerContext. Для каждой такой функции должен быть указан вход в таблице обработки команд.

    Создание приложений, выполняемых на WEB-сервере, в среде проектирования DELPHI

    Среда проектирования Delphi также позволяет создавать CGI и ISAPI приложения.

    Создание Web-форм В VisualStudio .NET

    Web-формы можно добавлять в следующие проекты .NET:
  • ASP.NET Web Site
  • ASP.NET. Web Service
  • Empty Web Site
  • Personal Web Site Starter Kit

  • Расположить проект можно как в файловой системе, так и на web-сервере. Если выбрано расположение HTTP, то для локального сервера поле Location следует установить равным http//localhost/каталог_проекта.
    При создании проекта типа ASP.NET Web Site мастер проекта формирует следующие файлы web -приложения:
  • Default.aspx - текст HTML-страницы:
  • Default.aspx.cs - подключаемые пространства имен и метод Page_Load.

  • В проект можно добавлять ранее созданные таблицы стилей.
    Таблицы стилей добавляются как новый элемент. При этом в проект добавляется файл с расширением css (например, StyleSheet.css).
    Следующий код иллюстрирует ASP-файл, используемый для отображения формы с 4 элементами управления:
    // Default.aspx.cs using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls;
    public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } } // Default.aspx <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

    Untitled Page
     


    // StyleSheet.css - файл таблицы стилей body { font-size: 18pt; color: blue; } .Cl1 { font-size: 24pt; color: red; }

    Листинг 28.3.

    Таблица стилей содержит набор селекторов с описанием стиля для каждого селектора. Селектором может быть имя тега, имя класса (указываемое после символа "."), имя идентификатора (указываемое после символа "#").

    Описание стиля для селектора указывается в виде списка, разделенного символами ";" и заключенного в фигурные скобки. Описание стиля состоит из пар "имя_атрибута: значение".

    Подключение таблицы стилей выполняется в заголовке HTML-файла строкой .

    Строка <%@ Page Language="C#" AutoEventWireup="true" CodeFile= "Default.aspx.cs" Inherits="_Default" %> содержит тег Page, представляющий HTML-страницу. Атрибут CodeFile указывает файл кода класса, производного от любого класса, наследуемого от System.Web.UI.Page. Атрибут Language определяет язык, используемый при компиляции конструкций вида <% %> и <%= %>. В качестве языка может выступать любой язык программирования, поддерживаемый .NET Framework, включая Visual Basic, C# или Jscript. Для любой страницы может быть указан только один используемый язык.

    Страницы ASP.NET состоят из двух частей:

  • визуальных элементов, включающих разметку, серверные элементы и статический текст;
  • программных фрагментов, включающих обработку событий и другой выполнимый код.


  • Технология ASP.NET предоставляет две модели управления визуальными элементами и кодом:

  • модель простого файла (single-file page model), при которой на странице описываются визуальные элементы, разметка и выполняемый код;
  • модель страницы с последующим кодом (code-behind page model), при которой на странице описываются визуальные элементы и разметка, а код размещается в отдельном файле (таком как Default.aspx.cs).


  • В следующей таблице приведен пример HTML-страницы, разработанной на базе этих двух моделей.


    Модель простого файлаМодель страницы с последующим кодом
    <%@ Page Language="C#" %> Single-File Page Model

    <%@ Page Language="C#" CodeFile="MyPage.aspx.cs" Inherits="MyPage" AutoEventWireup="true" %> Code-Behind Page Model

    // Файл MyPage.aspx.cs using System; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; public partial class MyPage : System.Web.UI.Page { protected void Button1_Click(object sender, EventArgs e) { Label1.Text = "Время: " + DateTime.Now.ToString(); } }
    Различие между двумя моделями ASP. NET страниц существует только на этапе проектирования. После компиляции страницы, спроектированные на базе различных моделей, представляются одинаковым образом.

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

    Этот же метод можно вставить и как скрипт в начало файла при использовании модели простого файла.

    Например

    // Форма:
    // Код метода: <%@ Page Language="C#" %>

    Создание Web-форм В VisualStudio .NET

    Таблица описания команд

    Для таблицы описания команд в MFC-библиотеку включены пять следующих макросов:
  • BEGIN_PARSE_MAP - определяет начало таблицы описания команд и указывает класс функций членов и базовый класс.
  • END_PARSE_MAP - определяет конец таблицы описания команд..
  • ON_PARSE_COMMAND - идентифицирует команду и указывает соответствующую ей функцию.
  • ON_PARSE_COMMAND_PARAMS - определяет список параметров обрабатываемой команды. Этот макрос должен следовать непосредственно за макросом ON_PARSE_COMMAND.
  • DEFAULT_PARSE_COMMAND - определяет команду, используемую в том случае, если нет явного указания выполняемой команды.

  • Макрос ON_PARSE_COMMAND используется при определении команды для объекта класса CHttpServer (или наследуемого от него), поступающей от клиента, и имеет следующее описание:
    ON_PARSE_COMMAND(FnName, mapClass, Args)
    Параметры:
    FnName - имя функции члена класса, а также и имя команды.
    mapClass - имя класса указанной функции.
    Args- указывает тип списка параметров и может принимать следующие значения
    ITS_EMPTY - параметров нет;
    ITS_PSTR - указатель на строку;
    ITS_RAW - данные, предварительно не обрабатываемые. Используется в том случае, если список параметров HTTP-запроса может иметь различное число параметров;
    ITS_I2 - значение типа short
    ITS_I4 - значение типа long
    ITS_R4 - значение типа float
    ITS_R8 - значение типа double
    ITS_I8 - значение типа 64-битовое integer
    ITS_ARGLIST - указатель на объект типа CHttpArgList.
    Например:
    BEGIN_PARSE_MAP(CDerivedClass, CHttpServer) DEFAULT_PARSE_COMMAND(Myfunc, CDerivedClass) // Для запроса типа // http://LOCALSERVER/MyISAPI_1.dll?Myfunc&string1&135 ON_PARSE_COMMAND(Myfunc, // Имя функции CDerivedClass, // Имя класса ITS_PSTR ITS_I2) // Список из двух параметров: // указатель на строку, значение типа short ON_PARSE_COMMAND_PARAMS("string integer=42")
    // Для запроса с тремя параметрами ON_PARSE_COMMAND(Myfunc2, CDerivedClass, ITS_PSTR ITS_I2 ITS_PSTR) ON_PARSE_COMMAND_PARAMS("string integer string2='Default value'") DEFAULT_PARSE_COMMAND(Myfunc3, CDerivedClass) ON_PARSE_COMMAND(Myfunc3, CDerivedClass, ITS_RAW) // Различное число параметров END_PARSE_MAP(CDerivedClass)
    // Функции, выполняемые для обработки команд void Myfunc(CHttpServerContext* pCtxt, LPTSTR pszName, int nNumber) { } // Первый параметр стандартен для всех функций, // обрабатывающих команды, тип второго и третьего // параметра был указан в макросе ON_PARSE_COMMAND void Myfunc2(CHttpServerContext* pCtxt, LPTSTR pszName, int nNumber, LPTSTR pszTitle) { } void CDerivedClass::Myfunc3( // Используется тип параметров // ITS_RAW CHttpServerContext* pCtxt, void* pVoid, // pVoid - указатель на передаваемые данные DWORD dwBytes) // dwBytes - количество переданных байтов данных { }
    Листинг 28.2.

    Выполнение ISAPI-приложения

    Для выполнения ISAPI-приложения соответствующую DLL-библиотеку следует поместить в каталог web-сервера. Таким сервером может быть Internet Information Server или любой другой web-сервер.
    Для просмотра сведений о виртуальных каталогах web-сервера на панели инструментов следует выбрать пиктограмму Administrative Tools и открыть диалог для администрирования web -сервера.
    Для IIS сервера следует выбрать пиктограмму Internet Information Services. Отображаемый далее диалог Internet Information Services (рис. 28.1) позволяет получать информацию и настраивать ISS сервер.
    Выполнение ISAPI-приложения
    Рис. 28.1.  Диалог Internet Information Services
    Для того, чтобы получить информацию о расположении домашнего каталога ISS-сервера, следует на панели, расположенной слева, выделить элемент Default Web Site и выполнить команду контекстного меню Properties.
    В диалоге Default Web Site Properties на странице Home Directory в поле Local Path указано расположение домашнего каталога. Для того чтобы из данного каталога можно было загружать как HTML-файлы, так и DLL-файлы, значение поля Executable Permissions должно быть установлено равным Script and Executables.
    После размещения ISAPI-приложения в домашнем каталоге web-сервера, это приложение можно выполнить в web-броузере, указав соответствующий URL-адрес.
    При выполнении приложения на локальном компьютере в качестве имени сервера указывается LOCALHOST.
    Например: http://LOCALHOST/MyISAPI_1.dll.
    При размещении ISAPI-приложения на web -сервере имя приложения можно изменить. На рис. 28.2 приведен результат выполнения в web-браузере описанного выше ISAPI-приложения.
    Выполнение ISAPI-приложения
    Рис. 28.2.  Выполнение ISAPI-приложения в web -браузере
    При первом выполнения ISAPI-приложения сервер загружает данную DLL. При всех последующих вызовах обращение происходит к уже загруженной DLL.

    Взаимодействие по протоколу TCP/IP

    Протокол TCP/IP (Transmission Control Protocol/Internet Protocol) предназначен для установления соединения между двумя компьютерами в сети, обычно называемыми клиентом и сервером. Протокол TCP/IP определяет IP-адрес и номер порта.
    IP-адрес задает имя компьютера в сети. IP-адрес указывается или как числовой идентификатор компьютера, или, при использовании сервера DNS, - как символьный псевдоним числового идентификатора.
    Локальный компьютер всегда адресуется как 127.0.0.1 или localhost.
    При работе в Интернете все используемые IP-адреса уникальны. Поэтому для задания своему ПК некоторого IP-адреса следует получить этот адрес у провайдера.
    При работе только в локальной сети предприятия можно самостоятельно установить различные IP-адреса для каждого ПК. Например: 192.168.0.2; 192.168.0.3; 192.168.0.4 и т.д.
    Номер порта - это значение, однозначно идентифицирующее некоторый логический порт приложения, через который можно получать и посылать данные.

    

        Биржевая торговля: Механические торговые системы - Создание - Программирование