- •Глава 1: Из истории создания C++
- •Глава 2: Обзор элементов языка C++
- •Глава 3: Основные типы данных
- •Глава 4: Инструкции управления
- •Глава 5: Массивы и строки
- •Глава 6: Указатели
- •Глава 7:Функции, часть первая: ОСНОВЫ
- •Глава 8: Функции, часть вторая: ссылки, перегрузка и использование аргументов по умолчанию
- •Глава 9: Еще о типах данных и операторах
- •Глава 10: Структуры и объединения
- •Глава 11: Введение в классы
- •Глава 12: О классах подробнее
- •Глава 13: Перегрузка операторов
- •Глава 14: Наследование
- •Глава 15: Виртуальные функции и полиморфизм
- •Глава 16: Шаблоны
- •Глава 17: Обработка исключительных ситуации
- •Глава 18: С++-система ввода-вывода
- •Глава 19: Динамическая идентификация типов и операторы приведения типа
- •Глава 20: Пространства имен и другие темы
- •Глава 21: Введение в стандартную библиотеку шаблонов
- •Глава 22: Препроцессор C++
- •Приложение А: С-ориентированная система ввода-вывода
- •Приложение Б: Использование устаревшего С++-компилятора
- •Приложение В: *.NET-расширения для C++
- •Предметный указатель
функций printf() и scanf(), за исключением того, что они работают с файлами. Именно поэтому эти функции обычно используются в С-программах. Прототипы функций fprintf() и fscanf() выглядят так.
int fprintf(FILE * fp, const char *fmt_string, ...);
int fscanf(FILE * fp, const char *fmt_string, ...);
Здесь параметр fp — файловый указатель, возвращаемый функцией fopen(). Функции fprintf() и fscanf() работают подобно функциям printf() и scanf() соответственно, за исключением того, что их действие направлено на файл, определенный параметром fp.
Удаление файлов
Функция remove() удаляет заданный файл. Ее прототип выглядит так.
int remove(const char *filename);
Она возвращает нуль при успешном удалении файла и ненулевое значение в противном случае.
Приложение Б: Использование устаревшего С++-компилятора
Программы, приведенные в этой книге, полностью соответствуют стандарту ANSI/ISO для C++ и могут быть скомпилированы практически любым современным С++-
компилятором, включая Visual C++ (Microsoft) и C++ Builder (Borland). Следовательно, при использовании современного компилятора у вас не должно быть проблем с компиляцией программ из этой книги. (В этом случае вам вообще не понадобится информация, представленная в этом приложении.)
Но если вы используете компилятор, созданный несколько лет назад, то при попытке скомпилировать наши примеры он может выдать целый список ошибок, не распознав ряд новых С++-средств. И в этом случае не стоит волноваться. Для того чтобы эти программы заработали со старыми компиляторами, нужно внести в них небольшие изменения. Чаще всего старые и новые С++-программы отличаются использованием двух средств: заголовков и пространств имен. Вот об этом и пойдет речь в этом приложении.
Как упоминалось в главе 2, инструкция #include включает в программу заданный заголовок. Для более ранних версий C++ под заголовками понимались файлы с расширением .h. Например, в старой С++-программе для включения заголовка iostream была бы использована следующая инструкция.
#include <iostream.h>
Вэтом случае в программу был бы включен заголовочный файл iostream.h. Таким образом, включая в старую С++-программу заголовок, необходимо задавать имя файла с расширением .h.
Вновых С++-программах в соответствии со стандартом ANSI/ISO для C++ используются заголовки другого типа. Современные заголовки определяют не имена файлов, а стандартные идентификаторы, которые могут совпадать с таковыми, но не всегда.
Современные С++-заголовки представляют собой абстракцию, которая попросту гарантирует включение в программу требуемой информации.
Поскольку современные заголовки необязательно являются именами файлов, они не должны иметь расширение .h. Они определяют имя заголовка, заключенного в угловые скобки. Вот, например, как выглядят два современных заголовка, подлерживаемых стандартом C++.
<iostream>
<fstream>
Чтобы преобразовать эти "новые" заголовки в "старые" заголовочные файлы, достаточно добавить расширение .h.
Включая современный заголовок в программу, необходимо помнить, что его содержимое относится к пространству имен std. Как упоминалось выше, пространство имен — это просто декларативная область. Ее назначение — локализовать имена идентификаторов во избежание коллизий с именами. Старые версии C++ помещают имена библиотечных функций в глобальное пространство имен, а не в пространство имен std, используемое современными компиляторами. Таким образом, работая со старым компилятором, не нужно использовать эту инструкцию:
using namespace std;
В действительности большинство старых компиляторов вообще не воспримут инструкцию using namespace.
Два простых изменения
Если ваш компилятор не поддерживает пространства имен и новые заголовки, он выдаст одно или несколько сообщений об ошибках при попытке скомпилировать первые несколько строк программ, приведенных в этой книге. В этом случае в эти программы необходимо внести только два простых изменения: использовать заголовок старого типа и удалить namespace-инструкцию. Например, замените эти инструкции
#include <iostream>
using namespace std;
такой.
#include <iostream.h>
Это изменение преобразует "новую" программу в "старую". Поскольку при использовании "старого" заголовка в глобальное пространство имен считывается все содержимое заголовочного файла, необходимость в использовании namespaee-инструкции отпадает. После внесения этих изменений, программу можно скомпилировать с помощью старого компилятора.
Иногда приходится вносить и другие изменения. C++ наследует ряд заголовков из языка С. Язык С не поддерживает современный стиль использования С++-заголовков, используя
вместо них заголовочные .h-файлы. Для разрешения обратной совместимости стандарт C++ по-прежнему поддерживает заголовочные С-файлы. Однако стандарт C++ также определяет современные заголовки, которые можно использовать вместо заголовочных С-файлов. В С ++-версиях стандартных С-заголовков к имени С-файла просто добавляется префикс 'c' и опускается расширение .h. Например, С++-заголовком для файла math.h служит заголовок <cmath>, а для файла string.h— заголовок <cstring>. Несмотря на то что в С++-программу разрешено включать заголовочный С-файл, против такого подхода у разработчиков стандарта есть существенные возражения (другими словами, это не рекомендовано). Поэтому в настоящей книге используются современные С++-заголовки во всех инструкциях #include. Если ваш компилятор не поддерживает С++-заголовки для С-заголовков, просто замените "старые" заголовочные файлы.
Приложение В: *.NET-расширения для C++
Разработанная компанией Microsoft интегрированная оболочка .NET Framework определяет среду, которая предназначена для поддержки разработки и выполнения сильно распределенных приложений, основанных на использовании компонентных объектов. Она позволяет "мирно сосуществовать" различным языкам программирования и обеспечивает безопасность, переносимость программ и общую модель программирования для платформы Windows. Несмотря на относительную новизну оболочки .NET Framework, по всей вероятности, в ближайшем будущем в этой среде будут работать многие С++-программисты.
Интегрированная оболочка .NET Framework предоставляет управляемую среду, которая следит за выполнением программы. Программа, предназначенная для помещения в оболочку .NET Framework, не компилируется с целью получения объектного кода. Вместо этого она переводится на промежуточный язык MSIL (Microsoft Intermediate Language), а затем выполняется под управлением универсального средства CLR (Common Language Runtime). Управляемое выполнение— это механизм, который поддерживает ключевые преимущества, предлагаемые оболочкой .NET Framework.
Чтобы воспользоваться преимуществами управляемого выполнения, необходимо применять для С++-программ специальный набор нестандартных ключевых слов и директив препроцессора, которые были определены разработчиками компании Microsoft. Важно понимать, что этот дополнительный набор не включен в стандарт C++ (ANSI/ISO Standard C++). Поэтому код, в котором используются эти ключевые слова, нельзя переносить в другие среды выполнения.
Описание оболочки .NET Framework и методов С++-программирования, необходимых для ее использования, выходит за рамки этой книги. Однако здесь приводится краткий обзор .NET-расширения языка C++ ради тех программистов, которые работают в .NET-среде.
Ключевые слова .NET-среды
Для поддержки .NET-среды управляемого выполнения С++-программ Microsoft вводит в
язык C++ следующие ключевые слова.
Краткое описание каждого из этих ключевых слов приведено в следующих разделах.
_ _abstract
Ключевое слово _ _abstract используется в сочетании со словом _ _gc при определении абстрактного управляемого класса. Объект _ _abstract-класса создать нельзя. Для класса, определенного с использованием ключевого слова _ _abstract, необязательно включение в него чисто виртуальной функции.
_ _box
Ключевое слов _ _box заключает в специальную оболочку значение внутри объекта. Такая "упаковка" позволяет использовать тип этого значения в коде, который требует, чтобы данный объект был выведен из класса System::Object, базового класса для всех .NET- объектов.
_ _delegate
Ключевое слово _ _delegate определяет объект-делегат, который инкапсулирует указатель на функцию внутри управляемого класса (т.е. класса, модифицированного ключевым словом _ _gc).
_ _event
Ключевое слово _ _event определяет функцию, которая представляет некоторое событие. Для такой функции задается только прототип.
_ _finally
Ключевое слово _ _finally — это дополнение к стандартному С++-механизму обработки исключительных ситуаций. Оно используется для определения блока кода, который должен выполняться после выхода из блоков try/catch. При этом не имеет значения, какие условия приводят к завершению try/catch-блока. Блок _ _finally должен быть выполнен в любом случае.
_ _gc
Ключевое слово _ _gc определяет управляемый класс. Обозначение "gc" представляет собой сокращение от словосочетания "garbage collection" (т.е. "сборка мусора") и означает, что объекты этого класса автоматически подвергаются процессу утилизации памяти, освобождаемой во время работы программы, когда они больше не нужны. В объекте отпадает необходимость в случае, когда на него не существует ни одной ссылки. Объекты _ _gc-класса должны создаваться с помощью оператора new. Массивы, указатели и интерфейсы также можно определять с использованием ключевого слова _ _gc.
_ _identifier
Ключевое слово _ _identifier позволяет любому другому ключевому слову языка C++ использоваться в качестве идентификатора. Эта возможность не предназначена для широкого применения и введена для решения специальных задач.
_ _interface
Ключевое слово _ _interface определяет класс, который должен действовать как интерфейс. В любом интерфейсе ни одна из функций не должна включать тело, т.е. все функции интерфейса являются неявно заданными чисто виртуальными функциями. Таким образом, интерфейс представляет собой абстрактный класс, в котором не реализована ни одна из его функций.
_ _nogc
Ключевое слово _ _nogc определяет неуправляемый класс. Поскольку такой (неуправляемый) тип класса создается по умолчанию, ключевое слово _ _nogc используется редко.
_ _pin
Ключевое слово _ _pin используется для определения указателя, который фиксирует местоположение в памяти объекта, на который он указывает. Таким образом, "закрепленный" объект не будет перемещаться в памяти в процессе сборки мусора. Как следствие, сборщик мусора не в состоянии сделать недействительным указатель, модифицированный с помощью ключевого слова _ _pin.
_ _property
Ключевое слово _ _property определяет свойство, являющееся функцией-членом, которая позволяет установить или получить значение некоторой переменной (члена данных класса). Свойства предоставляют удобное средство управления доступом к закрытым (private) или защищенным (protected) данным.
_ _sealed
Ключевое слово _ _sealed предохраняет модифицируемый им класс от наследования другими классами. Это ключевое слово можно также использовать для информирования о том, что виртуальная функция не может быть переопределена.
__try_cast
Спомощью ключевого слова _ _try_cast можно попытаться преобразовать тип выражения. Если предпринятая попытка окажется неудачной, будет сгенерировано исключение типа System::InvalidCastException.
_ _typeof
Ключевое слово _ _typeof позволяет получить объект, который инкапсулирует информацию о данном типе. Этот объект представляет собой экземпляр класса
System::Туре.
_ _value
Ключевое слово _ _value определяет класс, который представляет собой обозначение типа. Любое обозначение типа содержит собственные значения. И этим тип _ _value отличается от типа _ _gc, который должен выделять память для объекта с помощью оператора new. Обозначения типа, не представляют интерес для "сборщика мусора".
Расширения препроцессора
Для поддержки .NET-среды компания Microsoft определяет директиву препроцессора #using, которая используется для импортирования метаданных в программу. Метаданные содержат информацию о типе и членах класса в форме, которая не зависит от конкретного языка программирования. Таким образом, метаданные обеспечивают поддержку смешанного использования языков программирования. Все управляемые С++-программы должны импортировать библиотеку <mscorlib.dll>, которая содержит необходимые метаданные для оболочки .NET Framework.
Компания Microsoft определяет две pragma-инструкции (используемые с директивой препроцессора #pragma), которые имеют отношение к оболочке .NET Framework. Первая (managed) определяет управляемый код. Вторая (unmanaged) определяет неуправляемый (собственный, т.е. присущий данной среде) код. Эти инструкции могут быть использованы внутри программы для селективного создания управляемого и неуправляемого кода.
Атрибут attribute
Компания Microsoft определяет атрибут attribute, который используется для объявления другого атрибута.
Компиляция управляемых С++-программ
На момент написания этой книги единственный доступный компилятор, который мог обрабатывать программы, ориентированные на работу в среде .NET Framework, поставлялся компанией Microsoft (Visual Studio .NET). Чтобы скомпилировать управляемую программу, необходимо использовать команду /сlr, которая передаст вашу программу "в руки" универсального средства Common Language Runtime.