Система Orphus

C++/CLI: язык Visual C++ для среды .NET

Автор: Гордон Хогенсон
Издательство: Вильямс, 2007
464 страницы

Материал предоставил: Издательство ''Вильямс''
Найти в магазинах

Аннотация

Содержание
Предисловия
Объяснение дизайна C++/CLI
1. Краткий обзор
1.1. Ключевые цели
1.2. Основные базовые конструкции
1.3. Предыдущее усилие: Managed Extensions (Управляемые расширения)
Об авторе
О техническом рецензенте
Введение
Почему C++/CLI?
Об этой книге
Комментарии

Аннотация

Книга Гордона Хогенсона представляет собой описание нового языка C++/CLI, разработанного фирмой Microsoft для платформы .NET. В ней достаточно подробно описаны все отличия данного диалекта от базового языка Visual C++ и для каждого нового средства языка приведены короткие выразительные, законченные примеры, которые читатель может самостоятельно скомпилировать и выполнить. В некоторых случаях приведены более объемные реалистичные проекты. Книга может служить для первоначального знакомства с C++/CLI и будет полезна широкому кругу программистов, желающих ознакомиться с программированием для платформы .NET.

Содержание

Об авторах
Предисловия
Объяснение дизайна C++/CLI
Об авторе
О техническом рецензенте
Благодарности
Введение
Почему C++/CLI?
Об этой книге

Глава 1. Введение в C++/CLI

Сборка мусора и дескрипторы (маркеры)
Опция компилятора /clr
Виртуальная машина
Общая система типов
Ссылочные типы и типы значений
CLI и .NET Framework
''Hello, World''
Резюме

Глава 2. Быстрое знакомство с языковыми средствами C++/CLI

Примитивные типы
Составные типы
Ссылочные классы
Классы значений
Классы перечислений
Классы интерфейса
Элементы, моделирующие отношение ''имеет''
Свойства
Делегаты и события
Родовые типы
Резюме

Глава 3. Разработка C++/CLI-программ на базовой платфоме .NET Developer Platform с помощью Visual C++

Разработка программы с помощью Visual C++ 2005 на базовой платфоме разработки NDP
Режимы компиляции в Visual C++ 2005
Безопасный режим (опция компилятора /clr:safe)
Чистый режим (опция компилятора /clr:pure)
Смешанный режим (опция компилятора /clr)
Синтаксис управляемых расширений (опция компилятора /clr:oldSyntax)
Компиляция без указания опций
Предупреждения при компиляции старого кода в Visual C++ 2005
Зависимость от архитектуры и 64-разрядное программирование
Сборки и модули
Декларация сборки
Просмотр метаданных с помощью ILDasm.exe
Директива #using
Ссылка на сборки и управление доступом
Дружественные сборки
Атрибуты сборки
Компоновщик и компоновщик сборки
Ресурсы и сборки
Подписанные сборки
Мультифайловые сборки
Резюме

Глава 4. Семантика объекта в C++/CLI

Семантика объекта для ссылочных типов
Семантика объекта для типов значений
Последствия существования объединенной системы типов
Неявное упаковывание и распаковывание
Что лучше - семантика стека или кучи
Ловушки оператора удаления delete и семантики стека
Унарный оператор ''%'' и прослеживающая ссылка
Разыменование дескрипторов
Конструкторы копирования
Именующие выражения (адреса переменных), GC-именующие-выражен
значения переменных и GC-значения-переменных
auto_handle
Передача параметров
Передача ссылочных типов по значению
Передача типов значений по ссылке
Временные дескрипторы
Передача типов значений как дескрипторов
Семантика передачи параметров - итоговая таблица
Правила хорошего тона при возврате значений
Резюме

Глава 5. Базовые типы данных: строки, массивы и перечисления

Строки
Операции над строками
Сравнение строк
Форматирование строк
Ширина поля (или спецификатор выравнивания)
Форматирующие строки для чисел
StringBuilder
Преобразования строк в другие типы данных и обратные преобразования
Ввод-вывод
Базовые операции вывода
Out, Error (Ошибка) и In
Базовые операции ввода с пульта с помощью Console::ReadLine
Чтение и запись файлов
Чтение и запись строк
System::String и другие системы ввода-вывода
Массивы
Инициализация
Длина массива
Доступ к элементам массивов
Различия между родными и управляемыми массивами
Массивы как параметры
Копирование массива
Члены класса управляемого массива
Равенство массивов
Массивы в параметрах
Массивы в классах
За гранью массивов: ArrayList
Перечислимые типы
Класс перечисления
Перечислимые типы и преобразования
Основной тип перечисления
Признак Flags
Значения перечислений в качестве строк
Резюме

Глава 6. Классы и структуры

Конструкторы и инициализация
Статические конструкторы
Конструкторы копирования для ссылочных типов и типов значений
Литеральные области
Области initonly
Правильность констант
Свойства, события и операторы
Пример: игра Scrabble
Указатель this
Уровни доступа для классов
Родные и управляемые классы
Использование родных объектов в управляемом типе
Разрушение (уничтожение) класса и очистка
Финализаторы
Ловушки финализаторов
Резюме

Глава 7. Средства классов .NET

Свойства
Использование индексированных свойств
Делегаты и события
Асинхронные делегаты
События
Получатели и отправители события
Использование класса EventArgs
Зарезервированные имена
Перегрузка операторов
Статические операторы
Операторы преобразования и приведения
Приведения в C-стиле
Резюме

Глава 8. Наследственность

Коллизии имен в иерархиях наследственности
Использование зарезервированного слова new для виртуальных функций
Использование зарезервированного слова override для виртуальных методов
Абстрактные классы
Инкапсулированные классы
Модификаторы abstract и sealed
Виртуальные свойства
Специальные функции-члены и наследственность
Конструкторы
Виртуальные функции в конструкторе
Деструкторы и наследственность
Финализаторы и наследственность
Приведение в иерархиях наследственности
Резюме

Глава 9. Интерфейсы

Интерфейсы и абстрактные классы
Объявление интерфейсов
Интерфейсы, реализующие другие интерфейсы
Интерфейсы со свойствами и событиями
Коллизии имен интерфейсов
Интерфейсы и управление доступом
Интерфейсы и статические члены
Литералы в интерфейсах
Часто используемые интерфейсы .NET Framework
Интерфейсы и динамически загружаемые типы
Резюме

Глава 10. Исключения, атрибуты и отражение

Исключения
Иерархия исключений
Что находится в исключении?
Создание классов исключений
Использование finally-блока
Исключения в конструкторах
Вбрасывание неисключительных типов
Неподдерживаемые средства
Наилучшие методы обработки особых ситуаций
Исключения и ошибки родного кода
Атрибуты
Как работают атрибуты
Класс Attribute
Параметры атрибута
Некоторые полезные атрибуты
Сборка и атрибуты модуля
Создание пользовательских атрибутов
Отражение
Прикладные домены
Резюме

Глава 11. Параметризованные функции и типы

Родовые объекты
Типы-параметры
Родовые функции
Родовые типы
Родовые коллекции
Использование ограничений целостности
Ограничения целостности интерфейса
Ограничения целостности класса
Ссылочные типы и типы значений в качестве параметров-типов
Ограничение целостности gcnew
Ограничения целостности для типа значений
Ограничения целостности для ссылочных типов
Множественные ограничения целостности
Контейнерные типы .NET Framework
Сравнение родовых и неродовых контейнерных классов
Использование интерфейсов классов коллекций
ArrayList
Словари
Управляемые шаблоны
Резюме

Глава 12. Функциональная совместимость

Многогранность взаимодействия
Взаимодействие с другими языками .NET
Использование родных библиотек с помощью вызова базовой платформы
Маршализация данных
Взаимодействие с СOM
Использование родных библиотек без P/Invoke
Перекомпиляция родной библиотеки в управляемый код
Внутренние указатели
Скрепляющие указатели
Родные объекты и управляемые объекты
Использование управляемых объектов в родном классе
Использование родного объекта в управляемом типе
Родные и управляемые точки входа
Как избежать двойного переключения системного вызова
Управляемые и родные исключения
Взаимодействие со структурированными исключениями (__try/__except)
Взаимодействие с кодами ошибок Win32
Взаимодействие с исключениями C++
Взаимодействие с СOM HRESULT
Резюме

Приложение A. Справочник

Ключевые слова и контекстные ключевые слова
Ключевые слова с пробелами
Ключевые слова как идентификаторы
Обнаружение CLR-компиляции
XML-документация
Справка по режимам компиляции
Сводка синтаксических конструкций
Дескриптор (маркер)
Прослеживающие ссылки
Ключевое слово gcnew
Ключевое слово nullptr
Главный метод main
Управляемые массивы
Оператор for each (для каждого)
Ссылочные классы
Классы значений
Классы перечислений
Классы интерфейса
Безопасное приведение
Динамическое приведение
Статическое приведение
Приведение констант
Приведение в C-стиле
Модификаторы доступа
Объявление семантики стека
Области initonly
Литеральные области
Статический конструктор
Финализатор
Свойства
Делегаты
События
Статические операторы
Виртуальные функции
Абстрактные классы
Абстрактные методы
Инкапсулированные классы
Инкапсулированные методы
Реализация интерфейса
Явная реализация интерфейса
Исключения
Атрибуты
Идентификация типов
Шаблонные управляемые классы
Шаблонные управляемые функции
Родовые классы
Родовые функции
Внутренние указатели и скрепляющие указатели
Шаблон auto_handle
Класс блокировки
Шаблон gcroot
Шаблон auto_gcroot

Предметный указатель

Предисловия

Человек, стоящий на берегу реки, кричит другому, стоящему на противоположном берегу: 
- Как попасть на другой берег? 
Второй отвечает: 
- Вы стоите на другом берегу.
- Крис Госден

C++/CLI - привязка языка C++ к среде программирования .NET фирмы Microsoft. Она интегрирует C++ стандарта ISO с Объединенной системой типов (Unified Type System - UTS), рассматриваемой как часть общей языковой Инфраструктуры (Common Language Infrastructure - CLI). В ней предусмотрена поддержка исходных программ и функциональная совместимость исполнимых файлов, скомпилированных с родного и управляемого C++. Как видно из цитаты Криса Госдена, предлагается, что каждый путник пытается попасть на другой берег, независимо от того, где он оказался. Фактические детали того, как это происходит, описаны в блестящей книге Гордона.

В примитивных обществах и фантастических романах для юношей, таких как Властелин колец, который, наряду с Remembrance of Things Past ("Воспоминания о прошлых вещах"), стал одной из моих любимых книг; имена имеют своего рода волшебную ауру - с ними нужно обращаться очень осторожно и защищать их от порчи. То же самое, очевидно, верно и в информатике, или, по крайней мере, в пределах того, что предлагает Microsoft. Это первая книга, посвященная исключительно C++/CLI, я не мог найти никакой определенной справочной информации по C++/CLI, по крайней мере в Visual Studio 2005, и не смог в Visual C++ IDE открыть проект C++/CLI или даже обнаружить что-нибудь в документации в разделе What's New ("Новости"). Вся эта привязка C++ к .NET имеет своего рода налет фантазии, еще начиная с первоначальных управляемых расширений C++ в Visual Studio .NET выпуска 2001 года. C++/CLI - новая и весьма изящная замена управляемых расширений. Это то, как мы программируем .NET с помощью того, что в подзаголовке книги названо "Языком Visual C++ для .NET". Именно это вы и научитесь делать по книге Гордона.

Как указывает Гордон в его введении, C++/CLI представляет собой эволюцию C++. Это, конечно, не подразумевает, что язык C++/CLI лучше, чем C++; скорее C++/CLI лучше приспособлен к текущей и будущей вычислительной среде, в которой мы будем работать. Если вы запрограммировали в Visual C++ устаревшие "родные приложения" и должны перенести или расширить эти приложения для .NET, C++/CLI - основное (и абсолютно необходимое) инструментальное средство для вашего выживания, и книга Гордона - главный (и совершенно необходимый) первый шаг к овладению этим инструментальным средством.

В ходе эволюции увеличилась структурная сложность, и это также нашло отражение в C++/CLI: знание C++ может и не помочь понять C++/CLI! Например, в .NET существует такая вещь, как деструктор, и хотя его синтаксис напоминает синтаксис родного деструктора C++, его поведение странно противоречит интуиции; вы просто не можете полностью понять, как он работает, если знаете только, как действует его аналог. И именно здесь книга Гордона неоценима и как обучающая программа, и как настольная справочная система. По этой причине я настоятельно рекомендую ее.

Стэнли Б. Липпман (Stanley B. Lippman), архитектор Visual C++.

Объяснение дизайна C++/CLI

1. Краткий обзор

Ниже приведено извлечение из статьи A Design Rationale for C++/CLI Эрба Саттера (Herb Sutter). (Полный текст есть на сайте http://www.gotw.ca/publications/C++CLIRationale.pdf.)

Для разработки многочисленных приложений на C++ необходимы многие библиотеки, 
среды выполнения и среды разработки. 
Именно поэтому C++ был разработан уже к 1987 году; фактически он еще старше. 
Его корни на самом деле лежат во взгляде на C++ как на универсальный язык.
B. Stroustrup, Design and Evolution of C++ (Дизайн и эволюция C++). 
- Addison-Wesley Professional, 1994, p. 168)

Язык C++/CLI был создан для того, чтобы C++ можно было использовать во многих средах выполнения, удовлетворяющих стандарту ISO CLI (стандартизированное подмножество .NET).

Технология C++/CLI необходима для того, чтобы C++ можно было успешно использовать для построения приложений, в том числе и рассчитанных на Windows. Библиотеки CLI - базис для многих из новых технологий на базовой системе (платформе) Windows, включая библиотеку классов WinFX, поставляемую вместе с перспективной новой системой Windows Vista, которая предлагает более чем 10 000 классов CLI для всех нужд - от программирования Web-служб до новой трехмерной подсистемы графики. Языки, которые не поддерживают программирование на CLI, не обеспечивают прямого доступа к таким библиотекам, и программисты, которые хотят использовать такие функции, вынуждены использовать один из приблизительно 20 других языков, которые все-таки действительно поддерживают разработку в CLI. Среди языков, которые поддерживают CLI, отметим COBOL, ориентированный на решение экономических задач, C#, Eiffel, Java, Mercury, Perl, Python и др.; по крайней мере в двух из них связи между программами на разных языках стандартизованы на уровне языка.

Задача языка C++/CLI состоит в том, чтобы обеспечить программистам на C++ прямой доступ к существующим библиотекам CLI и дать возможность им создавать новые, с небольшими или вообще нулевыми накладными расходами во время выполнения, с минимальными затратами на дополнительные обозначения, обеспечив при этом полную совместимость с ISO C++.

1.1. Ключевые цели

Некоторые унификации были оставлены для будущего; например, предусмотрено расширение, для которого в C++/CLI преднамеренно оставлена свобода выбора: можно использовать new (новый) и "*", чтобы (с учетом семантики) распределить память для CLI-типа в куче C++, сделав его непосредственно доступным из существующих библиотек шаблонов C++, а можно использовать gcnew и "^", чтобы (с учетом семантики) выделить память для C++-типа в CLI-куче. Заметьте, что это было бы весьма проблематично, если бы в C++/CLI не использовался отдельный оператор gcnew и оператор объявления "^", чтобы добиться отделения CLI-функций от ISO C++.

1.2. Основные базовые конструкции

Четыре главных средства разработки программных моделей неоднократно упоминаются в этой работе.

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

С помощью классов можно представить почти все нужные нам понятия (концепции)... 
Расширение языка допускается только в том случае, 
если библиотечная рутина и в самом деле не может быть написана.
- B. Stroustrup, Design and Evolution of C++ (Дизайн и эволюция C++). - p. 181

В частности средство, которое неизбежно требует специального режима генерации кода, должно быть известно компилятору, а почти все средства CLI требуют специального режима генерации кода. Семантика многих средств CLI также не может быть выражена в C++. Библиотеки бесспорно предпочтительны везде, где возможно, но любое из этих требований исключает решение с помощью библиотеки. Заметьте, что языковая поддержка необходима даже в том случае, если разработчик языка попробует придать такой особенности вид языкового средства, представленного в библиотеке (т.е. даже выберет синтаксическую конструкцию, обманчиво подобную вызову библиотечной функции). Например, вместо

property int x; // A: синтаксис C++/CLI

разработчик C++/CLI мог бы использовать (среди многих других вариантов) вот такую синтаксическую конструкцию:

property<int> x; // B: синтаксис, подобный вызову библиотечного средства

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

Вообще, даже если синтаксис средства подобен библиотечному, это все равно не настоящее библиотечное средство в таких случаях:

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

Поэтому, выбор синтаксиса типа B ничего не изменил бы в техническом факте языкового расширения, а мог бы изменить только политическое восприятие. Этот подход придает языковому средству одеяние (с синтаксисом, подобным библиотечному средству), которое позволяет прикидываться тем, чем данное средство быть не может. Традиция C++ состоит в том, чтобы избегать волшебных библиотек, и потому библиотека стандартного C++ должна быть реализована в C++ без сговора с компилятором, хотя допускаются некоторые встроенные функции, известные компилятору или процессору. Язык C++/CLI предпочитает следовать традиции C++ и потому использует волшебные типы или функции только в четырех изолированных случаях: cli::array (массив), cli::interior_ptr, cli::pin_ptr и cli::safe_cast. Эти четыре средства могут рассматриваться как встроенные - их реализация поддерживается средой выполнения CLI, а их имена распознаются компилятором как теги данных средств среды выполнения CLI.

2. Важно не только скрыть ненужные различия, но также выделить основные (существенные) различия.

Я пытаюсь сделать существенные операции весьма заметными.
- B. Stroustrup, Design and Evolution of C++ (Дизайн и эволюция C++). - p. 119

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

void f()                      // пусто f()
{
    R r;// OK, концептуально распределяет R в стеке
    r.SomeFunc(); // OK, используем семантику значения
    ...
} // уничтожаем r здесь

В программной модели r находится в стеке и имеет обычную для C++ семантику на основе стека. Физически, компилятор генерирует нечто следующее:

// f, как сгенерировано компилятором
void f()                      // пусто f()
{
    R^ r = gcnew R;        // фактически распределяется в куче CLI
    r->SomeFunc();       // фактически использует косвенную ссылку
    ...
        delete r;// удаление r; r уничтожается здесь 
                 //      (память освобождается позже)
}

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

Например, хотя ссылки на объекты в CLI подобны указателям (например, они являются косвенными ссылками на объект), однако семантически они не то же самое, потому что они не поддерживают все те операции, которые поддерживают указатели (например, они не поддерживают арифметические операции над указателями, неизменяемость значений и достоверность сравнений). Если притворствовать и утверждать, что они являются теми же самыми абстракциями, хотя они ими не являются, да и не могут быть, то это может привести ко многим бедам. Один из основных дефектов в дизайне управляемых расширений (Managed Extensions) - то, что их пробовали подвести под многочисленные расширения C++, многократно используя оператор объявления "*", где T* неявно означает совершенно различные вещи, зависящие от типа T, - три совершенно различные и семантически несовместимые вещи, скрывающиеся вместе под единым синтаксисом.

Путь к нездоровому языковому дизайну выстелен хорошими намерениями и среди них - сокрытие существенных отличий.

3. Некоторые расширения действительно помогают следовать эволюции ISO C++ и C++0x .

Любые требования совместимости подразумевают некоторое уродство.
- B. Stroustrup, Design and Evolution of C++. (Дизайн и эволюция C++). - p. 198)

Действительное и важное достоинство расширений состоит в том, что использование расширения, которое установил бесстрастный и незаинтересованный комитет стандартов ISO C++ (WG21), позволяет наилучшим способом придерживаться эволюции C++0x, в нескольких случаях это было сделано явно в указании WG21.

Рассмотрим, например, следующее расширение синтаксиса цикла: язык C++/CLI, расширенный синтаксической конструкцией for each(T t in c) (для каждого (T t в c)). На консультации с рабочей группой WG21, следящей за эволюцией языка, которая собралась в Сиднее в марте 2004 года, и в других встречах члены EWG указали, что они интересовались таким средством, но им не понравились синтаксические конструкции for each (для каждого) и in (в) и они, вероятно, никогда не будут использовать их. От такого расширения C++/CLI, в котором используется нежелательные синтаксические конструкции, желательно держаться подальше. (При этом замечали, что, если в будущем WG21 когда-либо примет подобное расширение, то C++/CLI утратит свой синтаксис; его синтаксис совершенно изменится; поэтому C++/CLI должен идти по пути C++0x.)

Используя неподходящее расширение или не используя расширений вообще, но делая добавления к семантике существующей конструкции C++, вы рискуете отойти от эволюции C++0x. Рассмотрим еще один пример. Рассмотрим решение добавить оператор gcnew и оператор "^" в объявления... Рассмотрим только проблему совместимости: прибавляя в C++/CLI оператор объявления gcnew и оператор "^", которые, по всей вероятности, никогда не будут использоваться в ISO C++, вы избегаете конфликта с будущей эволюцией C++ (помимо объяснения, что эти операции не имеют никакого отношения к обычной куче C++). Если бы в C++/CLI вместо этого определить "новый оператор" new (gc) (новый (сборщик мусора)) или new (cli) с новым смыслом (т.е. сохранить стандартный синтаксис для распределения в куче CLI), то этот выбор, возможно, конфликтовал бы с эволюцией C++0x, в ходе которой могли бы потребоваться дополнительные формы оператора new с другим смыслом. И конечно, использование таких синтаксических конструкций с новым смыслом также конфликтовало бы с существующим кодом, в котором уже используются эти формы для размещения новых объектов, в частности, оператор new (gc), уже используется в популярном сборщике Boehm.

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

Мой опыт говорит, что люди увлекаются ключевыми словами настолько, 
что даже не могут представить понятия (концепции), 
если оно не имеет своего собственного ключевого слова. 
Этот эффект стал более важным и закоренелым, 
чем устно выраженная неприязнь людей к новым ключевым словам. 
Если есть выбор и время для рассуждения, 
люди неизменно предпочитают ввести новое ключевое слово.
- B. Stroustrup, Design and Evolution of C++. (Дизайн и эволюция C++). - p. 119.

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

В C++/CLI принято избегать прибавления зарезервированных слов, чтобы все его расширения были чистыми, но, тем не менее, признается, что программисты предпочитают ключевые слова. В C++/CLI эти требования сбалансированы, в нем ключевые слова прибавляются так, чтобы большинство незарезервированных слов не конфликтовало с пользовательскими идентификаторами.

По поводу этого см. также статью C++/CLI Keywords: Under the hood ("Ключевые слова C++/CLI: Под колпаком", 23 ноября 2003 года).

  1. Некоторые ключевые слова не конфликтуют с идентификаторами вообще, потому что они в соответствии с грамматикой помещаются в такой позиции, где идентификатор не может оказаться вообще (например, sealed (инкапсулированный)).
  2. Другие ключевые слова в соответствии с грамматикой могут появиться в той же самой позиции, что и пользовательский идентификатор, но конфликта удается избежать благодаря использованию другой продукции грамматики или же омонимия снимается семантически благодаря правилу, что предпочтение отдается семантике ISO C++ (например, property (свойство), generic (родовой)). Неофициально это правило может быть выражено так: "Если это может быть обычный идентификатор, то таковым он и является".
  3. Четыре идентификатора, использующиеся подобно библиотечным, считаются ключевыми словами, когда при поиске имени обнаруживается специальный тип маркера в пространстве имен cli (например, pin_ptr).

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

1.3. Предыдущее усилие: Managed Extensions (Управляемые расширения)

C++/CLI - второй публично доступный проект поддержки CLI-программирования на языке C++. Первая попытка была представлена фирмой Microsoft как Managed Extensions (управляемые расширения к C++), неофициально она называлась Managed C++ ("Управляемый C++"). Этот язык был представлен в двух выпусках Visual C++ (2002 и 2003) и продолжает поддерживаться как устаревший режим в Visual C++ 2005.

Поскольку при проектировании Managed Extensions особое внимание преднамеренно уделялось совместимости с C++, в нем было сделало две вещи, которые были полны благих намерений, но против которых возражали программисты.

Многие программисты на C++ пробовали усердно использовать эти средства, и в основном неудачно. Наличие Managed Extensions (Управляемых расширений) улучшало C++ настолько незначительно, что можно было CLI не поддерживать вообще. Однако Управляемые расширения (Managed Extensions) действительно помогли реальным пользователям обрести опыт в отношении того, что из CLI работало, а что не работало в их продуктах, и почему; и этот опыт непосредственно использовался для разработки C++/CLI.

Это были выдержки из статьи A Design Rationale for C++/CLI ("Объяснение дизайна C++/CLI"), написанной Эрбом Саттером.

Полный текст расположен на сайте http://www.gotw.ca/publications/C++CLIRationale.pdf.

Эрб Саттер (Herb Sutter), архитектор программного обеспечения.

Об авторе

Гордон Хогенсон (Gordon Hogenson) вырос в Фэрбенксе, на Аляске, и сохраняет независимый дух и любовь к природе, которую он познал там. Разрываясь между любовью к написанию книг и любовью к науке, в средней школе он написал фантастический роман Phalshazhaln и затем продолжал изучать химию в колледже Harvey Mudd, затем был интерном по химической физике в Университете штата Орегон и работал над диссертацией, чтобы получить степень доктора философии по физической химии в Вашингтонском университете, когда он опубликовал вместе с Уильямом П. Реинхардтом (William P. Reinhardt) работу в Journal of Chemical Physics по методам расчета, объединяющим квантовую механику и термодинамику, а также статью по методике медитации для первого выпуска Resonance Project, журнала по психоделической субкультуре.

Поддержанный товариществами от Конни Райнголда (Connie Ringold) и американским Министерством энергетики, он изучал квантовые жидкости и попытался примирить различные теории, более подходящие для философа-естественника, чем для современного ученого. Он провел часть своего времени, изучая противоречия на грани между наукой и философией. В момент критического безумного отвращения от проекта, посвященного работе на соискание степени доктора философии, он даже пробовал изучать древнегреческих ученых и запомнить отрывки из Илиады Гомера. Он позже использовал свою работу как магистерскую диссертацию. Он возвратился к более практическим проблемам в 1997 году и начал работу в Microsoft, тестируя Visual J++, C# и C++, а позже начал работу над программной документацией, где он в настоящее время любит управлять написанием технических проектов. Гордон познакомился со своей женой Джени во время наблюдений вечернего неба возле горы Рейнир (Rainier). Там они вместе как члены CSETI, организации занимающейся изучением внеземной жизни, искали признаки жизни вне Земли. Его текущее времяпрепровождение включает разведение козлов на его ферме рядом с городом Дюваль (Duvall), штат Вашингтон, планирование многолетнего сада и мечты об автономности на Земле.

О техническом рецензенте

Дамиан Ваткен (Damien Watkins) - руководитель проекта в группе Visual C++ в Microsoft. Его основной интерес - разработка и реализация архитектуры компонентов. Его первая книга, посвященная программированию в среде .NET, Programming in the .NET Environment (Addison-Wesley, 2003), была написана в соавторстве с Марком Хаммондом (Mark Hammond) и Брадом Aбрамсом (Brad Abrams). В ней описывается архитектура и цели .NET Framework. До присоединения к группе Visual C++ Team, Дамиан был членом External Research Office (Внешнего исследовательского управления) при исследовательском институте Microsoft в Кембридже. Дамиан представил обучающие программы, а также проводил семинары и симпозиумы по COM/DCOM, CORBA и .NET Framework на многочисленных собраниях, включая ECOOP 2004, OOPSLA 2003, OOPSLA 2002, SIGCSE 2002 и Microsoft Research Faculty Summit 2001.

Введение

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

Почему приходится расширять C++? C++ развивался многие годы; он используется миллионами разработчиков во всем мире. Синтаксис и семантика C++ должны были идти в ногу с развитием парадигмы программирования. В конце концов, хотелось расширить язык C так, чтобы поддержать в нем объектно-ориентированные концепции, которые были выдвинуты Бьярном Страуструпом (Bjarne Stroustrup) и его коллегами в Bell Labs. В соответствии с этим C должен был развиваться так, чтобы получился "C с классами". Многие из новых языковых средств были отражены в языке C++: шаблоны, типы данных во время выполнения и т.д.; эти средства расширили богатство (и увеличили сложность) языка. Средства, добавленные к C++ в C++/CLI, стали не исключением. В C++/CLI к языку C++ добавлено новое множество расширений, которые поддерживают новые концепции программирования, такие как компонентно-ориентированная разработка программного обеспечения, сборка мусора, функциональная совместимость с программами, написанными на других языках, которые выполняются на общей виртуальной машине, а также другие полезные средства.

CLI (Common Language Infrastructure, общая языковая инфраструктура), является стандартом, принятым ECMA International. В CLI определяется виртуальная машина и допускается богатый набор функциональных возможностей на языках, предназначенных для программирования виртуальной машины. Кроме того, CLI подразумевает такую структуру библиотек, которая поддерживает дополнительные средства, необходимые для реализации основных принципов программирования на виртуальной машине CLI. Все вместе эти библиотеки и базовая система (платформа) составляют инфраструктуру (основу) CLI. Это действительно общая языковая инфраструктура, потому что на ее основе может быть реализовано широкое разнообразие языков.

Название "C++/CLI" относится к стандарту, который описывает расширения языка C++, позволяющем программировать на виртуальной машине CLI.

Стандарт CLI, реализованный фирмой Microsoft, называется CLR, или общим языком времени выполнения, или базовой системой (платформой) .NET (.NET Developer Platform - NDP). Библиотеки, которые поставляет Microsoft для этого стандарта машины CLI, все вместе известны как Framework, хотя .NET Framework включает также другие библиотеки, которые не являются частью стандарта CLI. Есть несколько других реализаций CLI, включая .NET Compact Framework (http://msdn.microsoft.com/netframework/programming/netcf), Mono Project (http://www.mono-project.com) и dotGNU Portable.NET (http://dotgnu.org). Visual C++ 2005 - первый выпуск Visual C++, в котором поддерживается C++/CLI.

Сначала давайте обратимся к вопросу, что означает в техническом смысле термин "C++/CLI" . C++ - известный язык. В то время как некоторые могли бы придраться к соответствию стандартам, по существу дизайн языка C++ был зафиксирован в стандарте ANSI/ISO в конце 1990-х. Пуристы скажут, что C++/CLI - набор языковых привязок к стандарту CLI, а не язык сам по себе. ECMA принял C++/CLI как самостоятельный стандарт, и он был представлен соответствующей рабочей группе ISO. Язык C++/CLI - некоторое надмножество языка C++: если из языка удалить всю поддержку CLI, то останется C++. Это означает, что автоматически почти любая программа на C++ является программой на C++/CLI, просто как программа, которая не обращается ни к одной дополнительной функциональной возможности, предоставляемой CLI.

Почему C++/CLI?

C++/CLI был создан фирмой Microsoft как более дружественный язык программирования, чем его предшественник, Managed Extensions for C++ (C++ с управляемыми расширениями). Microsoft создала CLR, а группа C++ в Microsoft изобрела синтаксические конструкции, которые позволяли в программах на C++ использовать возможности CLR. Первым выпуском Visual Studio, поддерживающим CLR, была Visual Studio .NET 2002. Синтаксис, принятый в Visual Studio .NET 2002, был максимально приближен к существовавшему стандарту C++, т.е. к Стандарту ISO C++ (ISO C++ Standard). Согласно этому стандарту, любые расширения языка должны были соответствовать правилам для языковых расширений. Кроме других ограничений, это означало, что ключевые слова должны были начинаться с двойного подчеркивания (__). Таким образом, C++ с управляемыми расширениями имел столь неуклюжий синтаксис, что едва ли его можно было считать соответствующим CLR. Чтобы создать управляемый указатель (указатель, который ссылается на объект, участвующий в сборке мусора), использовалась следующая синтаксическая конструкция:

int __gc * ptr;               //int __сборщик мусора * ptr;

Ссылки на управляемые указатели имели вид "__gc указатель" ("__ указатель сборщика мусора"). Точно так же, чтобы объявить управляемый класс, использовалось зарезервированное слово __gc (сборщик мусора) как модификатор:

__gc class C { ... };         // __класс сборщика мусора C {...};

а чтобы объявить интерфейс (понятие, которое не существует как определенное языковое средство в C++), приходилось использовать следующую синтаксическую конструкцию:

__interface I { ... };        // __интерфейс;

Были добавлены и другие зарезервированные слова с двойными подчеркиваниями. В целом синтаксические конструкции были громоздкими.

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

Программирование должно быть развлечением. Язык - это нечто большее, чем только утилитарное понятие. В конце концов, много людей занимаются программированием весь свой рабочий день. Почему они должны мучиться из-за трудностей, связанных с расширением, если они могут использовать чистый, четкий язык, который делает программирование простым и развлекательным? Группа C++ в Microsoft поняла, что, для того чтобы сделать программирование на C++ приятным и эстетически совершенным, а также использовать все преимущества CLR, нужно изменить синтаксис. И это означало, что нужно сделать радикальный шаг - отступить от Стандарта ISO на язык C++.

Однако Microsoft приняла решение соблюдать стандарты, и уж если пришлось отступить от Стандарта ISO на C++, то, вместо того чтобы изобрести "нестандартный" язык, было решено ввести новый стандарт. Так родился стандарт C++/CLI.

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

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

Об этой книге

Цель этой книги состоит в том, чтобы познакомить вас с основами языка C++/CLI. Эта книга не представляет собой общее введение в Visual C++ 2005; некоторые средства Visual C++ 2005 эта книга не раскрывает вообще, к ним относятся, например, функции безопасности среды во время выполнения программ, написанных на C. Я хотел бы, чтобы эта книга использовалась как удобный настольный справочник; если вас интересует, как, скажем, объявляется массив или как ведет себя ссылка на класс, вы можете легко найти необходимую справку в этой книге. Я предполагаю, что вы уже "знаете C++", хотя, по правде говоря, лишь очень немного людей знают все то, что они должны знать о C++. Однако я предполагаю, что вы знаете приблизительно столько же, сколько знают большинство людей, которые программируют на C++. Я предполагаю, что вы хотите использовать это знание и, возможно, нуждаетесь в том, чтобы время от времени освежать ваши знания по C++. Я не предполагаю никакого знания CLR; если вы знаете (возможно, из C# или Visual Basic .NET) это средство, то вы обнаружите немного обзорной информации. Эта книга будет полезной как профессиональным разработчикам, начинающим работать с C++/CLI, так и студентам академических факультетов и людям, увлеченным своим хобби, т.е. изучением новых языков. В этой книге мы не будем обсуждать средства C++, которые не специфичны для расширения C++/CLI, несмотря даже на то, что C++/CLI позволяет использовать почти полностью язык C++. Ведь по классическому C++ есть много хороших справочников. (К ним, несомненно, относится книга C++ Primer, Fourth Edition, написанная Стэнли Липманом с соавторами (Stanley B. Lippman, Josee Lajoie и Barbara E. Moo, издательство Addison-Wesley, 2005) и книга The C++ Programming Language, Special Third Edition, написанная Бьярном Страуструпом (издательство Addison-Wesley, 2000).)

Кроме того, эта книга - вводная книга. Многие сложные темы объясняются не полностью, особенно функциональная совместимость между родным C++ и C++/CLI. Если вы захотите расширить свои знания после чтения этой книги, вы можете почитать книгу Маркуса Хиджа (Marcus Heege) Expert C++/CLI (издательство Apress, в печати), а если хотите получить подробную информацию об использовании .NET Framework в C++/CLI, вы должны прочитать книгу Pro Visual C++/CLI and the .NET 2.0 Platform, написанную Стивеном Фрейзером (Stephen R.G. Fraser), вышедшую в издательстве Apress в 2006 году.

Перефразируя Эйнштейна, одно из правил, которого я придерживался при написании этой книги, можно изложить так: объяснения должны быть настолько простыми, насколько это возможно, но проще. Я буду давать много примеров кода, которые можно понять сразу. Я надеюсь, что вам не понадобится много времени на детальное изучение текста и кода, имеющегося в этой книге, но вы сможете абсорбировать основную идею каждого примера кода и научитесь применять ее в ваших собственных проектах. Но, как и из любого правила, из этого есть исключения; в этой книге содержатся также более пространные примеры кода, которые предназначены для того, чтобы вы лучше почувствовали, как язык используется в более реалистических программах, и могли поразмышлять, как решить задачи с помощью C++/CLI.

В главе 1 "Введение в C++/CLI" я ввожу некоторые из фундаментальных понятий нового языка, и демонстрирую их на примере классической программы "Hello, World" в C++/CLI. Изучая ее, вы быстро познакомитесь с новым языком. Для этой же цели служит пример моделирования радиоактивного распада. Затем в главе 3 "Разработка C++/CLI-программ на базовой платформе .NET Developer Platform с помощью Visual C++" мы рассмотрим инфраструктуру независимо от языка программирования, что позволит вам оценить эффективность программы в этой среде, а в главе 4 "Семантика объекта в C++/CLI" мы рассмотрим семантику объекта в новом языке, а также смешивание родных и управляемых объектов. В главе 5 "Базовые типы данных: строки, массивы и перечисления" рассказывается о новых средствах C++/CLI, начиная непосредственно с самих средств CLI, таких как тип String (Строка) и ввод-вывод, а затем рассказывается о перечислимых типах и массивах. В главе 6 "Классы и структуры" описываются классы и структуры в C++/CLI. Затем рассмотрение классов продолжается в главе 7 "Средства классов .NET". Там изучаются новые элементы класса, такие как свойства, события и операторы. В главе 8 "Наследственность" описывается наследственность в C++/CLI. В главе 9 "Интерфейсы" обсуждаются интерфейсные классы, которые альтернативны традиционному множественному наследованию. Затем следует глава по другим языковым средствам; в ней рассказывается об обработке особых ситуаций, что является основным механизмом обработки ошибок в CLR; затем рассказывается об атрибутах, которые представляют собой метаданные для указания типа данных; потом обсуждается отражение, которое в C++/CLI является эквивалентом определения типа во время выполнения. После этого следует глава по параметризованным типам и классам-коллекциям, и, наконец, я завершаю введение в C++/CLI в главе 12 "Функциональная совместимость" более подробным обсуждением тех средств языка, которые поддерживают функциональную совместимость с существующим родным кодом C++ и другими языками .NET. Всюду по тексту я призываю вас экспериментировать с примерами кода и работать над вашими собственными программами так же, как и над приведенными в тексте. Коды примеров можно найти на сайте http://www.apress.com, и вы можете сами испытать C++/CLI, бесплатно загружая Visual C++ Express с сайта http://msdn.microsoft.com/vstudio/express. Вы можете также посетить мой блог на сайте http://blogs.msdn.com. Я надеюсь, что вы многому научитесь и очень полюбите читать эту книгу.

Комментарии