|
Часть 1
ЪДДДДДДДДДДї
і Файл ZTC і (c) Отделение 4 НФ ИТМ и ВТ
і 18.07.90 і ДДДДДДДДДДДДДДДДДДДДДДДДД
АДДДДДДДДДДЩ
Система программирования Z O R T E C H C + +
( Z O R T E C H C + + C O M P I L E R )
The World's First 'TRUE' C++ Compiler for MS-DOS Machines
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Первый в мире "истинный" компилятор С++ для машин с MS-DOS
В США поставляется фирмой
Zortech Inc, 366 Massachusetts Avenue, Arlington, MA02174
Tel: 617-646-6703, fax: 617-643-7969
и для всего остального мира фирмой UK Office:
Zortech Limited, 106-108 Powis Street, LONDON, SE18 6LU
Tel: 01-316-7777, fax: 01-316-4138
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і Перевод Руководства "Zortech C++ Compiler": і
і і
і Part One: The User Guide - Руководство пользователя і
і Part Two: The Reference Guide - Справочное руководство і
і Part Three: Function Library - Библиотека функций і
і Appendixes - Приложения і
і і
і Перевод выполнен в Новосибирском филиале і
і Института точной механики и вычислительной техники і
і им. С.А. Лебедева і
і і
і 630090, г. Новосибирск-90, і
і проспект академика Лаврентьева, 6 і
і НФ ИТМ и ВТ АН СССР і
і і
і Авторы перевода: Гутман А.А., Игнатенко П.С., і
і Касторнов Е.А., Степанов В.П і
і і
і Тел: (8-383-2)324-159, 324-144 і
і ДДДДДДД ДДДДДДД і
і і
і Новосибирск 1990 і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
Аннотация
Zortech C++ является первым кодопорождающим компилятором
для машин с MS-DOS. Это значит, что Вам не нужно тратить
деньги на С-компилятор. В самом деле, сейчас Вы держите в
руках ряд компонент: компилятор С++, С-компилятор, линкер
(редактор связей), библиотекарь, полное интегрированное ок-
ружение редактора, контекстно зависимые подсказки(help) и
библиотеку графики, самую скоростную из всех, какие Вы
когда-нибудь встречали!
Пользуясь Zortech C++, Вы имеете возможность совместно
использовать и согласовывать коды на C++, C, ассемблере, а
также связывать их воедино одной командой!
Zortech C++ включает полные библиотеки C++ и C, он сов-
местим с ANSI-стандартом на язык C. Zortech C++ уникален в
своей поддержке мыши, быстрого вывода на экран, повторно
входимой библиотеки вычислений с плавающей точкой и библио-
теки генерации звука.
Теперь Вы можете перенести Ваши коды из Microsoft C или
Turbo C в систему Zortech C++ - имеет место полная совмести-
мость библиотечных функций!
В Zortech C++ обеспечена также и совместимость с отладчи-
ком Codeview фирмы Microsoft!
Войдите в мир объектно-ориентированных систем программи-
рования(ООСП), используя Zortech C++!
Конечно, С велик, но С++ лучше!
Сравнительные показатели испытаний (benchmarks)
ЪДДДДДДДДДДДДДДДДВДДДДДДДДВДДДДДДДДДДВДДДДДДВДДДДДДДДДДї
іВид испытания іZortechCіZortechC++іTurboCіQuickC 1.0і
ГДДДДДДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДДДЕДДДДДДЕДДДДДДДДДДґ
іSieve ("решето")і 20.49 і 20.54 і 23.62і 22.72 і
іRsieve і 20.49 і 20.54 і 23.62і 22.03 і
іInteger і 1.32 і 1.38 і 6.31і 6.49 і
іFloat і 0.17 і 0.22 і 52.29і 51.03 і
і'Float і 32.73 і 37.74 і 52.39і 51.63 і
іPointer і 17.91 і 17.96 і 17.13і 16.87 і
іRpointer і 17.79 і 17.91 і 17.14і 16.64 і
іLoop і 3.90 і 3.90 і 3.90 і 3.90 і
іOptimize і 0.49 і 0.60 і 8.46 і 8.79 і
АДДДДДДДДДДДДДДДДБДДДДДДДДБДДДДДДДДДДБДДДДДДБДДДДДДДДДДЩ
Испытания проводились на ПЭВМ с микропроцессором 80286,
совместимой с IBM PC, с тактовой частотой 6 Мгц и без сопро-
цессора 8087
Лицензионное обращение фирмы Zortech
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
1. Пожалуйста, не раздавайте копии этого продукта своим
друзьям, склоняйте их к приобретению законной копии. Это
единственный источник вознаграждения программистов, техни-
ческих писателей и служащих фирмы Zortech за их невероятно
большой вклад в создание этого продукта.
2. Пожалуйста, не загружайте эту систему более чем на
одной ПЭВМ Вашего рабочего места - это незаконно и, кроме
того, лишает программистов и издателей их законных заработ-
ков.
3. С этой системой обращайтесь как с книгой: подобно
тому, как двоим нелегко читать одну и ту же книгу в одно
время, а каждому из них нужно приобрести собственную копию,
так и для пользования данным продуктом, пожалуйста, купите
узаконенную копию.
4. Zortech Ltd, ее филиалы, а также поставщики, дилеры и
служащие не могут нести финансовые потери, вызванные аварией
или слабостью этого продукта.
ПРЕДИСЛОВИЕ
Этот продукт является первым кодопорождающим компилятором
C++ для машин типа IBM PC/XT/AT. "Кодопорождающий" означает,
что Вам не требуется тратить массу денег на еще какой-либо
C-компилятор. Действительно, Вы только что приобрели и ком-
пилятор C++, и C-компилятор, и линкер, и библиотекарь, и
мощную утилиту make. Теперь Вам можно совместно использовать
и согласовывать коды C++, C и ассемблера. Мы включили "взры-
вной" редактор (ZED), который запускает компилятор, останав-
ливает компиляцию при обнаружении ошибки и соответственно
устанавливает курсор для облегчения исправления.
Zortech C++ включает полные библиотеки C++ и C, в т. ч.
поддержку мыши, быстрого вывода на экран, обращений к
BIOS/DOS и обработки прерываний. Для динамической отладки
можно воспользваться отладчиком Codeview фирмы Microsoft.
В целом, это мощная и недорогая объектно-ориентированная
система разработки программ для ПЭВМ.
C++ разработан в Bell Labs и представляет собой объектно-
-ориентированное расширение языка C. Поэтому Вы легко може-
те компилировать уже существующий C-код и использовать рас-
ширения по мере их освоения. В дополнение к этому, C++
обеспечивает лучший по сравнению с имеющимся в C контроль
ошибок, что помогает быстрее находить их. Поскольку C++ -
объектно-ориентированный язык, то Вы можете создавать собст-
венные типы данных. Это может сделать решение Ваших проблем
более четким. Например, разрабатывая систему картирования
погоды, Вы создаете тип данных под названием StormFront,
описываете несколько таких StormFront, перемещаете их,
комбинируете их, делаете дождливыми и т. д. Это высокоуров-
невое представление, на котором Вы можете решать более комп-
лексные задачи.
C++ поможет Вам легко переиспользовать старый код (даже
если это только объектные файлы без исходных текстов). Если
Вы астроном, а кто-то описал некий тип данных, названный
MassiveBody, который представляет собой не совсем то, что Вы
хотите, то Вы можете сказать: Asteroid - это MassiveBody
с соответствующими изменениями и дополнениями.
Вам даже не надо понимать, как работает MassiveBody, а
всего лишь надо знать, что он делает. Поскольку Вам потребу-
ется написать и отладить только изменения и дополнения, то
и результаты Вы получите скорее.
Пользуясь C++, Вы обнаружите, что структура языка практи-
чески организует Ваш код (структурирует программу). Начинай-
те с процесса создания каких-то частей Вашего проекта
(StormFront, Asteroid). Однажды отлаженные, они моменталь-
но интегрируются с остальными (и компилятор генерирует
ошибки, если Вы пытаетесь делать с типом что-нибудь, для
чего он не предназначен).
Цель C++ - помочь Вам программировать быстрее, причем без
потери эффективности, т. е. Вы увидите, что Ваши программы
на C++, как правило, такие же короткие и быстрые, как и
C-программы.
Группа разработчиков
Walter Bright - вдохновитель и руководитель работы
Bruce Eckel - C++ тексты и beta-тестирование
Bjorn Freeman - Benson - Zortech LINKER (редактор связей)
Steve Teal - Zortech HOTLINE
Joe Huffman - скоростная графическая библиотека
Nikki Locke - окружение редактора ZED
Kevin Powis - система контекстно зависимых подсказок HELP
Dave Morton - MANUAL (Руководство)
Mark Welsh - Подготовка руководства к печати
Dave Mansell - (техническое обеспечение)
Tanj Bennett - LIBRARIAN (библиотекарь)
Bjarne Stroustrup выражается особая признательность за
книгу по C++
С о д е р ж а н и е
Часть 1: Р У К О В О Д С Т В О П О Л Ь З О В А Т Е Л Я
БЫСТРЫЙ СТАРТ ........................................ 18
Кратко об установке
Кратко о редактировании ............................ 19
ВВЕДЕНИЕ В C++ ...................................... 21
Объектно-ориентированное программирование .......... 22
Эффективность ................................... 23
Краткие предварительные сведения
Объявления и описания
Прототипирование функций ........................ 24
Использование файлов заголовков для объявления классов
Краткое введение в потоки ....................... 25
Классы - определение Ваших собственных типов ....... 26
Полный пример ................................... 27
Совместное использование функций
(function overloading) ........................ 30
Совместное использование операций
(operator overloading) ........................ 32
Создание нового типа из старого типа ............... 34
По окончании базового курса ........................ 38
Дальнейшая помощь в работе
БОЛЕЕ СЛОЖНЫЙ C++ ................................... 39
Вызов функций-членов
Константы
Комментарии
Многократные включения файлов заголовков ........... 40
Области действия
Открытые (inline) функции .......................... 41
Функции доступа
Динамическое распределение памяти .................. 42
Конструкторы и деструкторы ......................... 43
Ссылки ............................................. 44
Совместное использование операций
(operator overloading) ........................... 47
Операция присваивания (operator=())
Указатель на void .................................. 49
Виртуальные функции
Друзья (friends) ................................... 51
Общие, приватные, защищенные (Public, Private, Protected)
Статические переменные ............................. 52
Операция разрешения области действия
Часть 2: С П Р А В О Ч Н О Е Р У К О В О Д С Т В О
ПОДРОБНОЕ РУКОВОДСТВО ПО УСТАНОВКЕ СИСТЕМЫ ........ 53
Системные требования
Установка системы на жесткий диск
Переменные окружения ............................ 54
Изменение маршрутов к каталогам (directory paths)
и переменных окружения ........................ 55
Переменная окружения CFLAGS ..................... 57
Установка системы на гибкий диск
КОНТЕКСТНО ЗАВИСИМЫЕ ПОДСКАЗКИ (Context sensiTive HELP) 57
Введение
Конфигурирование системы ........................... 58
Установка системы .................................. 59
Загрузка резидентного подсказчика
Удаление резидентного подсказчика
Вызов подсказки .................................... 60
Сводный список клавиш
ОКРУЖЕНИЕ РЕДАКТИРОВАНИЯ - ZED ....................... 61
Вход в редактор .................................... 62
Привязки клавиш .................................... 63
Функциональные клавиши ............................. 64
Клавиши управления курсором ........................ 65
Клавиши, совместимые с системой Wordstar ........... 66
Прочие управляющие клавиши ......................... 67
Дополнительные клавиши (клавиши с Alt)
Подсказки во время работы .......................... 70
О меню
Главное меню ....................................... 71
Меню "файлы" (Files) ............................... 72
Ввод имен файлов ................................ 74
Меню "размер" (Size) ............................ 76
Меню "перемещение курсора" (Moves)
Меню "редакция" (Edit) ............................. 78
Меню "размер" (Size) ............................ 81
Меню "блоки" (Blocks) .............................. 82
Меню "удаление" (Delete) ........................... 84
Меню "поиск" (Search) .............................. 85
Ввод строк ...................................... 86
Меню "прочее" (Other) ............................... 87
Ввод строк ...................................... 88
Компиляция
Компиляция проектов с многими исходными файлами 91
Отладка и исполнение программ ДОС
Проблемы с MS-DOS .................................. 92
Меню "запись" (Record) и "извлечение" (Playback) .... 93
Меню "текст" (Text) ................................ 94
Форматирование и автоматическая втяжка
(formatting and autoindent) ................... 95
Предыдущая версия файла ............................ 96
Структура меню
Конфигурирование ................................... 97
Установка быстрых командных клавиш (Hotkeys)
Установка маршрутов (Files) ..................... 104
Вид экрана (Screen)
Цвета экрана (Colors and More colors) ........... 107
Разметка экрана (Lines) ......................... 108
Позиции окон .................................... 109
Обрамление окон (Boxes)
Распечатка конфигурирации (Print) ............... 110
Сохранение конфигурации (saVe) и выход (eXit)
Файл подсказок
КОМПИЛЯТОР ZORTECH ................................... 111
Обзор процесса компиляции
ZTC1.EXE, ZTC1B.EXE и ZTCPP1.EXE ................ 112
Командная строка
Входной файл ................................. 113
Ключи
Переменные окружения ......................... 117
ZTG.EXE
Командная строка
Прочие ключи ................................. 118
ZTC2.EXE и ZTC2B.EXE ............................ 119
Входной файл
Ключи
Команда ZTC ..................................... 120
Переменные окружения ......................... 122
СПРАВОЧНИК ПО C++ ................................... 123
Комментарии
Идентификаторы
Ключевые слова
Конфликты с библиотечными именами
Литерные константы ................................. 124
Типы ............................................... 125
Kонстанты и неявно изменяющиеся переменные
(const и volatile)
Bнешние и глобальные переменные .................... 126
Выравнивание данных ................................ 127
Параметры функций
Указатели .......................................... 128
Инициализация
Операции с плавающей точкой
Препроцессор ....................................... 129
Макросы
Предопределенные макросы ........................... 130
Включаемые файлы ................................... 131
Прочие директивы препроцессора
Ограничения ........................................ 132
Прототипирование функций
Индуцированное прототипом приведение (cast) ..... 134
Прототипирование - char и float
Автопрототипирование
Совместимость с C .................................. 135
Определенные пользователем приведения типов ........ 136
Совместимость с C++ фирмы AT&T
Замечания, ошибки, предупреждения при программиро-
вании на C++ ..................................... 137
Совместное использование модулей на C и C++ ........ 138
Разное .......................................... 139
ПРОГРАММЫ РЕДАКТИРОВАНИЯ СВЯЗЕЙ ..................... 141
BLINK.EXE
Работа с ZTC .................................... 142
Использование
Ключи
Переменные окружения ........................... 143
Различия между BLINK и MS-LINK ................. 144
BUNCH.EXE ......................................... 145
Назначение
Работа с ZTC
Использование
.COM-файлы ..................................... 146
Переменные окружения
Пример
Ошибки
EXE2BIN.COM
Целочисленные программы ............................ 147
Создание .COM-программ
ИСПОЛНЕНИЕ ПРОГРАММ .................................. 148
Расширение командной строки аргументов ............. 149
Управление размером стека .......................... 150
ГЛОБАЛЬНЫЙ ОПТИМИЗАТОР ............................... 151
Введение
Что такое глобальная оптимизация
Зачем это нужно
Когда мне использовать его
Какого улучшения скорости можно мне ожидать ..... 152
Делает ли Глобальный оптимизатор ненужным програм-
мирование на ассемблере
Чего не умеет Глобальный оптимизатор
Использование ...................................... 153
Запуск оптимизатора посредством ZTC
Автономный запуск
Другие режимы ................................... 154
Дальнейшая информация .............................. 155
Распространение констант (+cnp)
Распространение копий (+cp)
Удаление излишних присваиваний (+da) ............ 156
Удаление неисполняемого кода (+dc)
Удаление излишних переменных,
вычисление границ существования,
распределение регистров при помощи раскраски (+dv)
Глобальные общие подвыражения (+gcse) ........... 157
Вынесение инвариантов из цикла (+li)
Индуктивные переменные цикла (+liv)
Итерация до отсутствия дальнейших оптимизаций(+loop)
Выполнять наше распределение регистров (+reg)
Соотношение между памятью и скоростью
(+space и +time)
Очень нагруженные выражения (+vbe) .............. 159
Советы и замечания
Использование ключевых слов const и volatile
Если возникли проблемы .......................... 160
СЛОЖНЫЕ ЧЕРТЫ СИСТЕМЫ ............................... 161
Модели памяти
Сегментная архитектура 8088/8086
Пять различных моделей [памяти] ................. 162
Выбор модели памяти
Указатели .......................................... 163
Ближние указатели
Дальние указатели
Макросы для работы с дальними указателями ....... 164
Нормализация дальних указателей
Арифметика над дальними указателями ............. 165
Использование ключевых слов near и far ............. 166
Использование ближних указателей ................ 167
Использование дальних указателей
Преобразования между ближними и дальними указателями
Подавление выравнивания в структурах ............... 168
Отладка C++ программ ............................... 169
Использование отладчиков
Другая поддержка
Отладка с CodeView ............................... 170
ИНСТРУМЕНТАРИЙ ........................................ 171
MAKE
Что такое MAKE
Начало работы с MAKE
Командный файл для MAKE (MAKEFILE) .............. 172
Пример MAKEFILE
Файлы зависимости ............................... 173
Второй пример
MAKEFILE при нескольких исходных файлах
Запуск MAKE ..................................... 174
Использование аргументов MAKE ................... 175
Определенные пользователем макросы .............. 176
Предопределенные макросы
Режимы исполнения правил ........................ 177
Внутренние команды MS DOS
Специальные цели ................................ 178
Перенаправление вывода
Неявные правила
Создание командных файлов для редактора связей ... 179
Список отличий от MAKE системы Юникс ............ 180
TOUCH
OBJTOASM ........................................... 181
Использование
ИНТЕРФЕЙС С АССЕМБЛЕРОМ ............................. 182
Программные разделы
T-модель памяти (.COM программы)
S-модель памяти ................................. 183
M-модель памяти ................................. 184
C-модель памяти ................................. 185
L-модель памяти ................................. 186
Общее размещение ................................... 188
Сборка подпрограмм
Область стека ...................................... 189
Возвращаемые функциями значения
Использование регистров ............................ 190
Выравнивание данных
Макросы из MACROS.ASM
Простой пример для S-модели ........................ 191
Следующий пример ................................... 193
Запуск MASM ........................................ 195
Часть 3: Б И Б Л И О Т Е К А Ф У Н К Ц И Й
БИБЛИОТЕКА ФУНКЦИЙ ................................... 196
Обмен с файлами .................................... 197
Виды файлов
Высокий и низкий уровни обмена с файлами
Распределение памяти ............................... 198
Куча (heap)
Стек ............................................ 199
Глобальные переменные .............................. 200
_8087
_okbigbuf ....................................... 204
_osmajor ........................................ 205
_osminor
_psp
errno
СООБЩЕНИЯ ОБ ОШИБКАХ ................................ 206
Ошибки ДОС
Ошибки математических функций ...................... 207
ФАЙЛЫ ЗАГОЛОВКИ ...................................... 207
assert.h
conio.h ............................................ 208
ctype.h
direct.h
disp.h
dos.h
fg.h ............................................... 209
errno.h ............................................ 211
int.h
io.h
limits.h
math.h
msmouse.h .......................................... 212
process.h
setjmp.h
signal.h
sound.h
stdarg.h
stddef.h ........................................... 213
stdio.h
stdlib.h
string.h ........................................... 214
sys\stat.h
time.h
БИБЛИОТЕЧНЫЕ ФУНКЦИИ ................................. 215
abort - СБРОСИТЬ ВЫПОЛНЕНИЕ ПРОГРАММЫ ............. 216
abs - АБСОЛЮТНОЕ ЗНАЧЕНИЕ ЦЕЛОГО ................. 217
acos - АРККОСИНУС ................................ 217
asctime - ДАТЬ ВРЕМЯ ............................. 218
asin - АРКСИНУС .................................. 219
assert - ПРОВЕРИТЬ УТВЕРЖДЕНИЕ .................. 220
atan, atan2 - АРКТАНГЕНС ......................... 221
atof, atoi, atol - ПРЕОБРАЗОВАТЬ В ПЛАВАЮЩЕЕ,
ПРЕОБРАЗОВАТЬ В ЦЕЛОЕ,
ПРЕОБРАЗОВАТЬ В ДЛИННОЕ ........ 222
bdos, bdosx - ВЫЗВАТЬ ФУНКЦИЮ DOS ................ 222
bioskey, _bios_keybrd - РАБОТА С КЛАВИАТУРОЙ ..... 223
bsearch - ДВОИЧНЫЙ ПОИСК В МАССИВЕ ................ 225
calloc - ДАТЬ ПАМЯТЬ ............................. 226
ceil - ЦЕЛАЯ ВЕРХНЯЯ ГРАНЬ ....................... 227
chdir - СМЕНИТЬ ТЕКУЩИЙ КАТАЛОГ .................. 227
_chkstack - ПРОВЕРИТЬ СТЕК ........................ 228
clearerr - СБРОСИТЬ ФЛАГ ОШИБКИ ................... 229
clock - ОПРЕДЕЛИТЬ ПРОЦЕССОРНОЕ ВРЕМЯ ............. 230
close - ЗАКРЫТЬ ФАЙЛ .............................. 230
cos, cosh - КОСИНУС, КОСИНУС ГИПЕРБОЛИЧЕСКИЙ ..... 231
creat - СОЗДАТЬ ФАЙЛ .............................. 232
ctime - ДАТЬ КАЛЕНДАРНОЕ ВРЕМЯ ................... 233
difftime - ОПРЕДЕЛИТЬ ОТРЕЗОК ВРЕМЕНИ ............ 234
Display Package - Пакет отображения .............. 235
div - ДЕЛИТЬ ..................................... 239
DOS Package - Пакет функций DOS .................. 240
ecvt - ПРЕОБРАЗОВАТЬ ЧИСЛО В СТРОКУ .............. 242
execl - execvp - ЗАПУСТИТЬ ПРОЦЕСС ................ 243
exit, _exit - ЗАВЕРШИТЬ ВЫПОЛНЕНИЕ ПРОГРАММЫ ...... 245
exp - ЭКСПОНЕНТА ................................. 246
fabs - АБСОЛЮТНОЕ ЗНАЧЕНИЕ ВЕЩЕСТВЕННОГО ......... 247
farcalloc - farrealloc - РАБОТА С ДАЛЬНЕЙ КУЧЕЙ ... 248
_farptr_norm, _farptr_fromlong, _farptr_tolong -
НОРМАЛИЗОВАТЬ ДАЛЬНИЙ УКАЗАТЕЛЬ,
ДАЛЬНИЙ УКАЗАТЕЛЬ ИЗ ДЛИННОГО,
ДАЛЬНИЙ УКАЗАТЕЛЬ В ДЛИННОЕ ...... 249
fclose - ЗАКРЫТЬ ФАЙЛ ............................ 250
fcvt - ПРЕОБРАЗОВАТЬ DOUBLE В СТРОКУ С ФИКСИРО-
ВАННОЙ ТОЧКОЙ ............................. 251
feof - ПРОВЕРКА ПРИЗНАКА КОНЦА ФАЙЛА ............. 252
ferror - ПРОВЕРКА ПРИЗНАКА ОШИБКИ В ФАЙЛЕ .......... 253
fflush - ВЫТОЛКНУТЬ БУФЕР ФАЙЛА .................. 254
fgetc - ВЗЯТЬ БАЙТ ИЗ ФАЙЛА ...................... 254
fgets - ВЗЯТЬ СТРОКУ ИЗ ФАЙЛА .................... 255
fileno - ДАТЬ ДЕСКРИПТОР ФАЙЛА .................... 256
filesize - ДАТЬ РАЗМЕР ФАЙЛА ...................... 257
findfirst, findnext - ПОИСК ФАЙЛОВ ПО ШАБЛОНУ ....... 257
floor - ЦЕЛАЯ ЧАСТЬ .............................. 259
flushall - ВЫТОЛКНУТЬ БУФЕРА ВСЕХ ОТКРЫТЫХ ФАЙЛОВ 259
fmod - ОСТАТОК ОТ ДЕЛЕНИЯ ДВУХ ЧИСЕЛ .............. 260
fopen - ОТКРЫТЬ ФАЙЛ ............................. 261
FP_OFF, FP_SEG - СЕГМЕНТ, СМЕЩЕНИЕ ............... 262
fprintf - ФОРМАТНЫЙ ВЫВОД В ФАЙЛ ................. 263
fputc - ЗАПИСЬ БАЙТА В ФАЙЛ ...................... 263
fputs - ЗАПИСЬ СТРОКИ В ФАЙЛ ..................... 264
fread - ЧИТАТЬ ИЗ ФАЙЛА .......................... 265
free - ОСВОБОДИТЬ ПАМЯТЬ ......................... 266
freopen - ОТКРЫТЬ ФАЙЛ ПОВТОРНО .................. 266
frexp - ЭКСПОНЕНЦИАЛЬНОЕ ПРЕДСТАВЛЕНИЕ ........... 267
fscanf - ФОРМАТНЫЙ ВВОД ИЗ ФАЙЛА ................. 268
fseek - ПОЗИЦИОНИРОВАТЬ ФАЙЛ ..................... 269
fstat - ВЗЯТЬ СТАТУС ФАЙЛА ....................... 270
ftell - ДАТЬ ПОЗИЦИЮ В ФАЙЛЕ ..................... 271
fwrite - ПИСАТЬ В ФАЙЛ ........................... 272
getc, getchar, getche, getch - ВЗЯТЬ БАЙТ ИЗ ФАЙЛА 273
getcwd - ДАТЬ ТЕКУЩИЙ КАТАЛОГ .................... 274
getDS - ВЗЯТЬ ЗНАЧЕНИЕ РЕГИСТРА DS ................ 275
getenv - ДАТЬ ОКРУЖЕНИЕ .......................... 275
gets - ВВОД СТРОКИ ............................... 276
hypot - ГИПОТЕНУЗА ............................... 277
index - НАЙТИ ЛИТЕРУ В СТРОКЕ .................... 277
inp, inpw - ВВОД ИЗ ПОРТА ........................ 278
Interrupt Package - Пакет работы с прерываниями ... 279
int86, int86x - ПРОГРАММНОЕ ПРЕРЫВАНИЕ ........... 282
intdos, intdosx - СИСТЕМНЫЙ ВЫЗОВ ФУНКЦИИ DOS .... 283
isatty - ОПРЕДЕЛИТЬ ТИП ПОТОКА ................... 284
is package - Пакет классификации литер ........... 285
itoa - ПРЕДСТАВЛЕНИЕ ЦЕЛОГО ...................... 287
kbhit - ПРОВЕРКА ВВОДА С КЛАВИАТУРЫ .............. 288
labs - АБСОЛЮТНОЕ ЗНАЧЕНИЕ ДЛИННОГО .............. 288
ldexp - ЭКСПОНЕНТА ............................... 289
ldiv - ДЕЛЕНИЕ ЧИСЕЛ ТИПА long .................... 290
localtime - ДАТЬ МЕСТНОЕ ВРЕМЯ ................... 291
log, log10 - ЛОГАРИФМ ............................ 292
longjmp - ДЛИННЫЙ ПЕРЕХОД ........................ 292
lseek - ИЗМЕНИТЬ ПОЗИЦИЮ В ФАЙЛЕ ................. 294
malloc - ОТВЕСТИ ПАМЯТЬ .......................... 295
matherr - ОБРАБОТКА ОШИБКИ МАТЕМАТИЧЕСКОЙ ФУНКЦИИ 296
memchr - memset - РАБОТА С БАЙТАМИ В МАССИВАХ ..... 296
mkdir - СОЗДАТЬ КАТАЛОГ .......................... 298
MK_FP - СОЗДАТЬ ДАЛЬНИЙ УКАЗАТЕЛЬ ................ 299
mktime - ПРЕОБРАЗОВАТЬ ВРЕМЯ ..................... 299
modf - ДРОБНАЯ И ЦЕЛАЯ ЧАСТЬ ЧИСЛА ................ 300
Mouse Package - Пакет работы с мышью ............. 301
open - ОТКРЫТЬ ФАЙЛ ............................... 302
outp, outpw - ВЫВОД В ПОРТ ....................... 304
peek - ПЕРЕСЛАТЬ БУФЕР ИЗДАЛЕКА .................. 305
perror - ВЫДАТЬ СООБЩЕНИЕ ОБ ОШИБКЕ .............. 306
poke - ПЕРЕСЛАТЬ БУФЕР ДАЛЕКО .................... 307
poly - ПОЛИНОМ ................................... 308
pow - СТЕПЕНЬ .................................... 309
printf, fprintf, sprintf - ФОРМАТНЫЙ ВЫВОД ........ 309
putc, putchar - ВЫВОД ЛИТЕРЫ В ФАЙЛ ............... 313
puts - ВЫВОД СТРОКИ В ФАЙЛ ........................ 314
qsort - БЫСТРАЯ СОРТИРОВКА ТАБЛИЦЫ ................ 315
raise - ВОЗБУДИТЬ СИГНАЛ ......................... 316
rand - СЛУЧАЙНАЯ ВЕЛИЧИНА ........................ 317
read - ЧИТАТЬ БЛОК ИЗ ФАЙЛА ....................... 317
realloc - ПЕРЕРАЗМЕСТИТЬ БЛОК ПАМЯТИ .............. 318
rename - ПЕРЕИМЕНОВАТЬ ФАЙЛ ....................... 319
rewind - УСТАНОВИТЬ В НАЧАЛО УКАЗАТЕЛЬ ФАЙЛА ..... 320
rmdir - УДАЛИТЬ КАТАЛОГ .......................... 321
sbrk - УВЕЛИЧИТЬ СЕГМЕНТ ДАННЫХ .................. 322
scanf - ФОРМАТНЫЙ ВВОД ........................... 323
segread - ЧИТАТЬ СЕГМЕНТНЫЕ РЕГИСТРЫ ............. 326
setbuf - УСТАНОВИТЬ БУФЕР В/В .................... 327
setjmp - УСТАНОВИТЬ ТОЧКУ ДЛИННОГО ПЕРЕХОДА ...... 328
setvbuf - УСТАНОВИТЬ БУФЕР В/В ................... 328
signal - УСТАНОВИТЬ РЕАКЦИЮ НА СИГНАЛ ........... 330
sin, sinh - СИНУС, СИНУС ГИПЕРБОЛИЧЕСКИЙ ......... 332
Sound Package - Пакет работы со звуком ........... 332
spawn - СОЗДАТЬ ПРОЦЕСС .......................... 333
sprintf - ФОРМАТНЫЙ ВЫВОД В БУФЕР ................ 334
sqrt - КВАДРАТНЫЙ КОРЕНЬ ......................... 335
srand - ИНИЦИАЛИЗАЦИЯ СЛУЧАЙНОЙ ВЕЛИЧИНЫ ......... 335
sscanf - ФОРМАТНЫЙ ВВОД В БУФЕР .................. 336
stat - ЧИТАТЬ СТАТУС ФАЙЛА ....................... 337
strcat - strdur - Работа со строками ............. 338
strerror - ПОЛУЧИТЬ ИНФОРМАЦИЮ ОБ ОШИБКЕ .......... 339
strlen - ДАТЬ ДЛИНУ СТРОКИ ........................ 340
strlwr - ПРИВЕСТИ К НИЖНЕМУ РЕГИСТРУ ............. 341
strncat - strpbrk - Работа со строками ........... 341
strrchr - strset - Работа со строками ............ 343
strspn - ДАТЬ ДЛИНУ СОВПАДАЮЩЕЙ ПОДСТРОКИ ........ 344
strstr - НАЙТИ ПОДСТРОКУ ......................... 344
strtod - strtoul - ПРЕОБРАЗОВАТЬ ИЗ А/Ц ВИДА ..... 345
strupr - ПРИВЕСТИ К ВЕРХНЕМУ РЕГИСТРУ ............ 347
swab - ПОПАРНО ПОМЕНЯТЬ БАЙТЫ .................... 348
system - ОБРАЩЕНИЕ К DOS ......................... 348
tan, tanh - ТАНГЕНС, ТАНГЕНС ГИПЕРБОЛИЧЕСКИЙ ..... 349
time - ДАТЬ ВРЕМЯ ................................ 350
toascii, tolower, toupper - В ASCII, В НИЖНИЙ,
В ВЕРХНИЙ ............ 351
ungetc - ВОЗВРАТИТЬ ЛИТЕРУ ........................ 352
unlink - УДАЛИТЬ ФАЙЛ ............................ 353
utime - ИЗМЕНИТЬ ВРЕМЯ МОДИФИКАЦИИ ФАЙЛА ......... 353
va_arg - va_start - РАБОТА С ПЕРЕМЕННЫМ ЧИСЛОМ
ПАРАМЕТРОВ ................... 354
vfprintf, vprintf, vsprintf - ФОРМАТНЫЙ ВЫВОД ..... 355
write - ПИСАТЬ В ФАЙЛ ............................. 356
ВВЕДЕНИЕ В БЫСТРУЮ ГРАФИКУ ......................... 358
Определение базовой координатной системы
Типы переменных
Константы FG ....................................... 359
Адаптеры графического дисплея
Доступ к координатам рамок и линий ................. 360
Маски .............................................. 361
Запись режимов
Типы линий
Доступные цвета .................................... 362
ОБЩИЕ ПЕРЕМЕННЫЕ ..................................... 363
fg_displaybox (КООРДИНАТЫ РАМКИ ДИСПЛЕЯ)
fg_charbox (КООРДИНАТЫ РАМКИ ЛИТЕРЫ)
fg_ncolormap (РАЗМЕР ПАЛИТРЫ)
fg_nsimulcolor (ЧИСЛО ЦВЕТОВ) ..................... 364
fg_pixelx, fg_pixely (РАЗМЕРЫ ПИКСЕЛЯ)
fg_numpages (ЧИСЛО СТРАНИЦ)
fg_display (ТИП АДАПТЕРА)
fg_activepage (НОМЕР АКТИВНОЙ СТРАНИЦЫ) ........... 365
fg_displaypage (НОМЕР ОТОБРАЖАЕМОЙ СТРАНИЦЫ)
ФУНКЦИИ, ПОСТАВЛЯЕМЫЕ ПОЛЬЗОВАТЕЛЕМ ФАКУЛЬТАТИВНО ...... 365
_assert - УТВЕРЖДЕНИЕ
fg_lineclip - КЛИППИРОВАНИЕ ЛИНИИ ................ 366
ОБЩИЕ ФУНКЦИИ БЫСТРОЙ ГРАФИКИ ...................... 366
fg_adjustxy - СКОРРЕКТИРОВАТЬ ТЕКУЩИЕ КООРДИНАТЫ 366
fg_blit - ПЕРЕМЕСТИТЬ РАМКУ ...................... 367
fg_box_cpy - СКОПИРОВАТЬ РАМКУ ................... 368
fg_drawarc - НАРИСОВАТЬ ДУГУ ..................... 368
fg_drawbox - НАРИСОВАТЬ ПРЯМОУГОЛЬНИК ............ 369
fg_drawdot - НАРИСОВАТЬ ТОЧКУ .................... 370
fg_drawellipse - НАРИСОВАТЬ ЭЛЛИПС ............... 370
fg_drawline fg_drawlinep - НАРИСОВАТЬ ЛИНИЮ ...... 371
fg_drawlineclip - ОТКЛИППИРОВАТЬ И НАРИСОВАТЬ ЛИНИЮ 372
fg_drawmatrix - НАРИСОВАТЬ МАТРИЦУ ............... 372
fg_drawthickline - НАРИСОВАТЬ ТОЛСТУЮ ЛИНИЮ ...... 373
fg_fillbox - ЗАПОЛНИТЬ ПРЯМОУГОЛЬНИК ............. 374
fg_flush - ВЫТОЛКНУТЬ НА ДИСПЛЕЙ ................. 374
fg_getcolormap - ЧИТАТЬ ПАЛИТРУ (КАРТУ ЦВЕТОВ) .... 371
fg_init - ИНИЦИАЛИЗИРОВАТЬ БЫСТРУЮ ГРАФИКУ ....... 375
fg_init_null - fg_init_vga12 - ИНИЦИАЛИЗИРОВАТЬ FG 376
fg_line_cpy - КОПИРОВАТЬ ЛИНИЮ ................... 377
fg_putc - ВЫВЕСТИ ЛИТЕРУ ......................... 377
fg_puts - ВЫВЕСТИ СТРОКУ ......................... 378
fg_readbox - ЧИТАТЬ РАМКУ ........................ 378
fg_readdot - ЧИТАТЬ ТОЧКУ ........................ 379
fg_restore - ВОССТАНОВИТЬ ........................ 380
fg_save - СОХРАНИТЬ .............................. 380
fg_setactivepage - УСТАНОВИТЬ АКТИВНУЮ СТРАНИЦУ ... 381
fg_setcolormap - УСТАНОВИТЬ ПАЛИТРУ .............. 381
fg_setdisplaypage - УСТАНОВИТЬ ДИСПЛЕЙНУЮ СТРАНИЦУ 382
fg_setlinepattern УСТАНОВИТЬ ШАБЛОН ЛИНИИ ......... 382
fg_term - ПЕРЕЙТИ В РЕЖИМ А/Ц ТЕРМИНАЛА .......... 383
fg_writebox - ПИСАТЬ РАМКУ ....................... 383
П Р И Л О Ж Е Н И Я
ПРИЛОЖЕНИЕ 1: Zorlib - Библиотекарь ................ 384
Библиотекарь Zortech
Что такое библиотекарь
Использование Zorlib ............................ 385
Диалоговый режим Zorlib ......................... 387
Использование командных файлов
Ресурсы
Замечания
ПРИЛОЖЕНИЕ 2: СООБЩЕНИЯ ОБ ОШИБКАХ ................. 388
Сообщения компилятора об ошибках
ZTC1, ZTCPP1 и ZTC1B
Ошибки в C++ расширениях
Ошибки стандартного C ........................... 391
Сообщения об ошибках от редактора связей ........ 399
Сообщения об ошибках от Zorlib .................. 404
Предупреждения
Сообщения об ошибках
Системные ошибки ............................. 405
Сообщения об ошибках от MAKE
Сообщения об ошибках от глобального оптимизатора 407
Сообщения об ошибках времени исполнения ......... 408
ПРИЛОЖЕНИЕ 3
Переход от предыдущих версий Zortech C компилятора .. 409
Общие блоки
Литерные
Модели памяти
Предопределенные макросы ........................ 410
Препроцессор
Арифметика над дальними указателями
Измененные библиотечные функции
Редакция связей ................................. 411
Интерфейс с языком ассемблера
ПРИЛОЖЕНИЕ 4 .......................................... 412
Полная таблица кодов ASCII ......................... 412
Часть 1
Р У К О В О Д С Т В О П О Л Ь З О В А Т Е Л Я
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
БЫСТРЫЙ СТАРТ
ДДДДДДДДДДДДД
Кратко об установке
Прежде, чем начать разрабатывать программы на C++ исполь-
зуя Zortech C++, необходимо правильно настроить Ваши диски.
Данное руководство по быстрой генерации предназначено
для пользователей, имеющих жесткие диски.
За более детальной информацией по установке отсылаем к
части 2,разделу:"Подробное руководство по установке системы".
Установку Zortech C++ на жестком диске выполняет файл
ZTCSETUP.EXE. При исполнении этой программы будет создан ка-
талог C:\ZORTECH и ряд подкаталогов.
До запуска ZTCSETUP Вам нужно сделать копию дистрибутив-
ных дисков и для инстолляции использовать эти рабочие копии.
В дальнейшем Вам следует хранить и дистрибутивы, и рабочие
дискеты в надежном месте.
Для запуска ZTCSETUP установите дискету #1 рабочей копии
системы в накопитель A:. Если у Вас текущее приглашение не
A>, то перейдите на него, набрав A: и затем нажав .
Имея приглашение A:>, наберите:
ZTCSETUP
Далее следуйте инструкциям на экране. По мере копирования
файлов с каждой дискеты Вас будут приглашать ставить следую-
щую дискету. И, ставя ее, Вы должны быть твердо уверены в
том, что она является той, которая требуется.
По окончании копирования дискет включите следующие строки
в конец Вашего файла AUTOEXEC.BAT:
SET PATH=C:\ZORTECH\BIN
(либо добавьте в строку PATH списка текущих маршрутов и
;C:\ZORTECH\BIN )
SET INCLUDE=C:\ZORTECH\INCLUDE
(В этом каталоге находятся включаемые файлы)
SET LIB=C:\ZORTECH\LIB
(В этом каталоге находятся библиотечные файлы)
Если у Вас имеется RAM-диск (электронный диск, диск в до-
полнительной оперативной памяти), то можно добавить также
SET TMP=d:
где d: - это имя накопителя RAM-диска. Кроме того, рекомен-
дуется добавить в файл CONFIG.SYS следующие две строки:
BUFFERS=20
FILES=20
Если Вам захочется, чтобы контекстно зависимые подсказки
загружались автоматически, то Вам нужно вставить в файл
AUTOEXEC.BAT следующую строку:
ZTCHELP
А теперь перезапустите машину для настройки нового окружения.
Кратко о редактировании
Вход в редактор является простым, если система установле-
на с дистрибутива так, как описано выше. Перейдите в ката-
лог, в котором Вы хотите хранить исходные файлы, и наберите:
ZED
Вы войдете в редактор программ. Если Вам хочется вызвать
редактируемый файл при входе в редактор, то используйте сле-
дующий альтернативный синтаксис (если, например, Ваш файл
называется MYPROG.CPP): ZED MYPROG.CPP и в этом случае:
если файл не существует, то он будет создан и открыт для ре-
дактирования; иначе откроется существующий файл.
Теперь можно набирать Вашу С++ программу.
Отметим, что обычно C++ файлы имеют расширение .cpp.
Для таких файлов автоматически используется C++-компи-
лятор, как и C-компилятор для файлов с расширением .c.
Можно принудительно использовать компилятор C++ для
всех файлов, если воспользоваться флагом _cpp компиля-
ции (детали см. в части 2: Справочное руководство).
Файлы заголовков (header files) для C++ обычно имеют
расширение .hpp.
Запустите ZED согласно вышеприведенному описанию и набе-
рите программу:
#include
main()
{
cout << "Hello Bjarne!\n";
}
проверьте правильность набора и затем войдите в меню, нажав
Esc. Kлавишами со стрелками переместите подсвеченную полоску
на пункт Others и нажмите кл. Enter (или же просто нажмите
букву o [лат.]). А теперь таким же способом из следующего
меню [подменю] выберите опцию cOmpile.
Здесь ZED просит задать некоторые флаги [т.е. режимы]
компиляции либо другую информацию, такую как дополнительные
библиотечные файлы. Нажав F1, Вы получите список имеющихся
опций, а также их описание. Если в поле ввода уже имеется
какой-либо текст, то его можно удалить, нажав F9. Окружение
запоминает флаги компилятора, использованные при последней
компиляции, и устанавливает их таковыми по умолчанию. Введи-
те флаг компилятора для компактной модели памяти, т.е.
-mc
Если пример набран правильно, программа откомпилируется.
Если в процессе компиляции встретится ошибка, то управление
возвращается редактору с позиционированием курсора на строке
с ошибкой. Следует отметить, что причина ошибки могла быть
выше этой строки, но сразу не была обнаружена анализатором.
При успешном окончании компиляции Вам выдается приглаше-
ние для ввода командной строки аргументов Вашей программы.
Нажимайте клавиши: Enter - для немедленного исполнения прог-
раммы, Esc - для возврата в редактор. Если Вы не сохранили
программу, то в данной точке Вам следует сделать это, ис-
пользуя опцию FS.
[Два способа сохранения файла: После нажатия кл. Esc Вы
попадете в меню режимов, здесь последовательно нажмите буквы
f, s - файл сохраняется, Вы остаетесь в системе C++; нахо-
дясь в редакторе, нажмите две клавиши одновременно Alt-v -
файл сохранится, и Вы переходите в DOS.
Вариант первого способа: перемещение подсвеченной полоски
по элементам меню при помощи клавиш со стрелками и нажатие
кл. Enter на нужном элементе].
В нашем примере подобной проблемы нет; Вы можете просто
нажать Enter для исполнения программы. Вы увидите приветст-
венное обращение к Bjarne, а также приглашение нажать любую
клавишу для возврата в ZED.
Итак, Вы с помощью Zortech C++ откомпилировали и испол-
нили Вашу первую программу.
Выход из редактора тоже прост. Нажмите клавишу Esc для
входа в режим меню, если Вы уже не находитесь в нем, и набе-
рите FX (что вызывает переходы Files, eXit). Выдается зап-
рос подтверждения необходимости сохранения каждого изменен-
ного буфера.
За более подробной информацией по компиляции и компоновке
C++-программ отсылаем к части 2: Справочное руководство.
ВВЕДЕНИЕ В С++
ДДДДДДДДДДДДДДДД
Данное Руководство составлено в предположении, что у Вас
есть опыт работы на языке C. А если нет, имеются дюжины
подходящих книг. Например, неплохо выбрать книгу "C Primer
Plus", авторы Waite, Prata, and Martin, в которой имеется
глава по C++.
Если Вы уже знаете C, то Вам легко будет подняться до
C++, поскольку нет нужды учить весь язык сразу. Вы сможете
программировать точно так же, как если бы Вы находились в C,
добавляя особенности C++ по мере их изучения.
Имеются еще две книги, которые Вам стоит приобрести:
"An Introduction to Object-Oriented Programming and C++",
авторы Richard Wiener и Lewis Pinson (издательство Addison-
Wesley 1988), которая вводит C-программиста в C++ и содержит
ряд полезных примеров, и "The C++ Programming Language",
автор Bjarne Stroustrup - создатель C++ (издана Addison-Wes-
ley 1986). Эта книга является "экспертным руководством" по
С++ и содержит много маленьких, но искусных и продвинутых
примеров. Здесь рассматривается сложный материал, и она яв-
ляется "последним словом" по языку. Обе книги поставляются
фирмой Zortech.
Две следующие главы предназначены для того, чтобы Вы про-
чувствовали язык программирования C++ и Zortech C++ в осо-
бенности и освоили бы дополнительные возможности, которые
предлагает C++ по сравнению со своим предшественником - C.
Они не претендуют на роль глубокого руководства, и мы реко-
мендуем Вам купить одну или обе упомянутые выше книги с
тем, чтобы Вы достигли профессионализма в языке. Книги можно
заказать в Zortech.
Объектно-ориентированное программирование (ООП)
Цель объектно-ориентированного программирования - повыше-
ние производительности труда программиста. Язык помогает Вам
структурировать Ваши программы, а также переиспользовать код,
который Вы или кто-то другой уже написали. Чем меньше рабо-
ты по написанию программы, тем выше Ваша производительность.
Объектно-ориентированные языки позволяют Вам создать нечто,
называемое классом. Класс определяет новый тип данных. После
завершения определения класса компилятор обрабатывает его
точно так же, как если бы он был типом данных, встроенным в
язык подобно типу целого(integer) или чисел с плавающей точ-
кой (float). Все, что требуется сделать для класса как
встроенного типа, включая контроль ошибок, выполняет компи-
лятор. Описание новых классов часто называется описанием
абстрактных типов данных.
Если у Вас имеется некоторый класс, и Вам нужен несколько
отличный от него, то не требуется возвращаться и изменять
класс. Можно просто сказать: "определить новый класс,
который суть старый вышеописанный класс плюс некоторые
изменения и дополнения, которые я хочу сделать". Это [перео-
пределение] называется наследованием или порождением произ-
водного типа - Вы "производите" новый тип из старого или,
другими словами, в новом классе "наследуете" свойства старо-
го. Описание классов таким способом избавляет Вас от массы
работы.
Объектно-ориентированному языку требуется больше, чем
абстрактные типы данных и производные типы. Если у Вас вна-
чале имеется единственный класс, часто называемый базовым,
и из него порождается ряд классов, то Вам потребуется
управлять производными классами из базового. Например, пусть
базовый класс - shape и порожденные: line, circle и square,
причем в каждом из них используются разные алгоритмы рисова-
ния. Тем не менее, можно создать список из shapes (форм) и
отрисовать (draw) каждую из них [по своему алгоритму], не
зная, что рисуется: круг, квадрат или прочее. Это свойство,
часто называемое "полиморфизмом" (commonality), означает:
объект сам уточняет во время исполнения, что именно делать с
Вашим сообщением. (Полиморфизм не возникает автоматически -
смотри пункт о виртуальных функциях).
Вот краткое определение ООП:
Abstract Data Typing + Type Derivation + Commonality
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД-
(Абстрактные типы данных + порождение производных типов +
полиморфизм)
Вы поймете смысл этих терминов при изучении особенностей
языка. А пока запомните лишь, что C++ поможет Вам программи-
ровать более производительно.
Эффективность
В прошлом объектно-ориентированные языки были очень неэф-
фективными. И хотя программист пишет программы достаточно
быстро, а на машине они исполняются все же медленно и требу-
ют больших ресурсов. Например, в общем случае, нужно загру-
жать все окружение разработки программы при ее исполнении.
И это делает "солидную" программную поддержку громоздкой.
Когда Bjarne Stroustrup в Bell Laboratories приступил к
созданию C++, он отказался жертвовать скоростью и эффектив-
ностью использования памяти, присущими C. Он также заимст-
вовал присущий C "минималистский" подход: ядро языка включа-
ет возможности, которых достаточно для создания всего того,
что можно только вообразить. Если средства ядра Вам не под-
ходят, то Вы можете самостоятельно "расширять" язык путем
создания новых классов.
Итак, C++ предоставляет Вам эффективный по скорости
исполнения программ компилятор наряду с его преимуществами
для разработки объектно-ориентированных программных систем.
Краткие предварительные сведения
Объявления и описания
Это на самом деле С, но важно понять различие между опи-
саниями и объявлениями, в особенности, когда речь идет о
C++. Объявление - это сообщение компилятору. Оно не генери-
рует объектного кода. Оно просто говорит: "вот так выглядит
эта функция: ее имя, что она возвращает и стандартное обра-
щение к ней. А сам код Вы увидите несколько позже." Объявле-
ние сообщает компилятору, что это не ошибка, если Вы видите
вызываемую подобным образом функцию; ошибкой является, если
функция не вызывается именно таким способом. Вот пример
объявления:
double foo(int i, long j, float bar);
В случае C, если Вы не объявили функцию до ее использова-
ния, то все нормально: компилятор предполагает, что она воз-
вращает тип int, и не контролирует передаваемые ей параметры,
так что Вы можете передавать любое количество параметров лю-
бого типа. В случае C++ контроль типов усилен. Существует
мало случаев, когда можно обойтись без объявления функции
до ее использования. Описание функции - это код, который
точно говорит, как работает функция.
Прототипирование функций
Обратите внимание, что в приведенном выше примере задано
не только имя функции, но также и тип каждого из параметров.
Такой подход знаком программистам на Паскале и называется
прототипированием функций. Оно позволяет компилятору прове-
рять правильность вызова функции. В случае C Вы не задавали
[типов] параметров при объявлении функции. А при обращении к
функции Вы могли бы передать ей любое количество параметров
любого типа и компилятору до этого нет дела - это обуславлива-
ет все виды ошибок [передачи фактических параметров]. Новый
ANSI-стандарт на C (и соответственно Zortech C компилятор,
следующий стандарту) требует прототипирования функций.
Зортеховский C++ выполняет автопрототипирование. Если Вы
не описали функцию до ее использования, то компилятор смот-
рит и определяет прототип при первом обращении к функции.
Использование файлов-заголовков для объявления классов
При создании нового типа данных Вы описываете класс в це-
лом: имя нового типа данных, какие данные он содержит, что
за функции работают с ним. Такие описания классов обычно
относятся в файл заголовков. Любой, кто хочет использовать
класс, просто включает (#include) этот заголовочный файл.
Тем самым компилятору сообщается, что класс существует, и
что можно с ним делать. Если же Вы пытаетесь делать что-то
некорректно, то компилятор Вам об этом сообщит.
К примеру, предположим, что имеется класс, называемый
box, который Вы можете расписать (fill) тремя целыми, а по-
том опустошить (empty). Заголовочные файлы Zortech C++
обычно оканчиваются расширением .hpp и поэтому пусть заголо-
вочный файл box называется box.hpp. Ниже приводится пример
того, как можно использовать боксы:
#include "box.hpp"
/* сообщает компилятору, что такое box */
main()
{
box B1, B2; /* создадим несколько boxes */
B1.fill(1,2,3);
B2.fill(10,11,12); /* заполним их */
B1.empty();
B2.empty(); /* очистим их */
}
Как здесь видно, использование кем-то описанного класса
весьма просто.
Краткое введение в потоки
"Потоки" (streams) - это заранее определенный набор клас-
сов для обмена с консолью и файлами. Они более естественны и
намного легче в использовании, чем библиотечные функции в
просто C (хотя Вы можете, конечно, продолжать использование
printf(), scanf() и т.п. - C++ не препятствует использованию
простых C-функций). В простом C стандартный ввод/вывод вы-
полняется с стандартными файлами: ввода-stdin, вывода-stdout
и файлом обработки ошибок-stderr. В случае потоков им экви-
валентны cin, cout и cerr ( и дополнительно cprn и caux для
принтера и дополнительных портов).
Основная идея состоит в следующем. Имеется несколько
объектов для организации в программе ввода/вывода. И все,
что Вам нужно сделать, - это отправить запрос к ним, и они
сработают. Для работы с потоковыми объектами используются
операции << и >>,которые имеют особый смысл в случае исполь-
зования с потоками (это называется совместным использованием
операций или перегрузкой операций (Operator Overloading);
см. пункт "Совместное использование операций". Например,
пусть направляется несколько чисел для стандартного вывода :
#include
/* объявление потоковой библиотеки */
main()
{
int a = 1, b = 2, c = 20;
double pi = 3.14;
cout << a; /* выводит значение a; можно
включать литералы и строки сов-
местно */
cout << "b = " << b << "\n";
cout <<"c должно быть = "<< 20 << "c = " << c << "\n";
/* что произойдет, если выполнить
все совместно? */
cout <
class OriginalWork {
char author[20];
char title[20];
int month, day, year;
int value;
public:
/* во-первых, нечто, называемое "конструктором" */
OriginalWork (char * Auth, char * name, int m,
int d, int y, int val);
void print();
}; /* Существенно наличие точки с запя-
той после закрывающей скобки */
Здесь мы подошли к понятию чего-то нового - конструктора.
Заметим, что имя конструктора - то же, что и класса.
Компилятор вызывает конструктор, когда объект объявляется;
поэтому можно включить в конструктор код, выполняющий авто-
матическую инициализацию. В нашем конструкторе окажется, что
все значения в объекте будут инициализированы. Запишем код
для OriginalWork в файле OWORK.CPP. Он подобен записи C кода
за исключением того, что:
* каждое имя функции-члена должно быть связано с классом,
для которого она пишется, при помощи операции C++ ::
* функции-члены имеют доступ к элементам структуры данных
классов.
#include "owork.hpp"
/* кавычки для файлов в текущем каталоге */
#include
/* углы для файлов в каталоге include */
#include
OriginalWork::OriginalWork (char * Auth, char * name,
int m, int d, int y, int val)
{
month = m; day = d; year = y;
value = val;
strcpy(author, Auth); /* обращение к C-функции */
strcpy(title, name);
}
void OriginalWork::print()
{
cout << "name: " << title << "\n";
cout << "Author: " << author << "\n";
cout << "Created on: " << month << "/" << day << "/"
<< year << "\n";
cout << "Value: $" << value << "\n";
}
Необычность конструктора состоит в том, что Вам не нужно
говорить, какое значение он возвращает - компилятор уже
знает это (это указатель на сам объект).
Окончательно мы можем использовать класс таким образом
(назовем этот файл MAIN.CPP):
#include "owork.hpp"
main()
{
OriginalWork painting("Bob Rembrandt",
"Blue Boy",5,24,65,74);
OriginalWork photo(Eisenstadt", "Moon",6,30,77,2000);
OriginalWork chapter("Bruce Eckel", "Intro to C++,
5,24,88,0);
painting.print();
photo.print();
charter.print();
}
Поскольку мы показали эту программу в виде трех разных
составляющих (OWORK.HPP, OWORK.CPP и MAIN.CPP), то Вам надо
откомпилировать в объектные модули файлы OWORK.CPP и
MAIN.CPP и скомпоновать их в итоговый .EXE файл, названный
ART.EXE, командой:
ZTC -oART.EXE MAIN OWORK
При этом также будут сгенерированы объектные файлы
OWORK.OBJ и MAIN.OBJ. Вместо этого можно собрать все в
единственный файл ART.CPP и оставить команду:
ZTC ART
Это может быть очень удобно для небольших программ и для
их тестирования. Однако, Вы увидите, что большинство проек-
тов будет содержать массу классов, находящихся в различных
кодовых файлах и файлах заголовков, и многие из них уже от-
компилированы в объектные модули. Большая часть работы по
организации программы просто состоит во включении файлов за-
головков при использовании классов внутри Вашей главной
(main) процедуры и сборке всех объектных модулей, содержащих
откомпилированный код для классов.
Заметим, что термин "объектный" использован здесь в исто-
рическом смысле, а не в объектно-ориентированном: исходный
код - это отправная точка, а объектный код создается компи-
лятором и помещается в объектные модули откомпилированного
кода с расширением .OBJ. Эта терминология неудачна и вызыва-
ет путаницу, но она была разработана до того, как возникло
объектно-ориентированное программирование.
Для создания программы, которая состоит из многих незави-
симо откомпилированных объектных модулей, Вам стоит написать
командный файл MS DOS (.BAT), в который включаются все необ-
ходимые команды. Это должно сокращать затраты на набор, но
не время: всякий раз, когда Вы создаете Вашу программу, весь
исходный код должен быть перекомпилирован независимо от
того, изменялся он или нет. Существует более разумный способ
подобной организации: см. главу Инструментарий, где описана
служебная программа make.
Совместное использование функций (function overloading)
В нашем втором полном примере введем понятие совместного
использования функции (function overloading). Это означает,
что у Вас может быть много функций с одним и тем же именем,
но с разными аргументами, а компилятор будет выбирать подхо-
дящую функцию. Это весьма хорошее свойство, так как детали
остаются скрытыми, и Ваш код делается более легко читаемым.
Вероятно, наиболее часто встречаемым примером совместного
использования функций являются конструкторы. Обычно сущест-
вует несколько путей создания объекта. Например, пусть соз-
дан класс, названный date; он может быть инициализирован
тремя целыми числами, строкой, представляющей дату, или
вообще при отсутствии данных (и в этом случае используется
текущая дата).
#include
class date {
int month, day, year; // месяц, день, год
public:
date(); /* нет начального значения - текущая дата */
date(int m, int d = 1, int y = 88);
date(char * datestring);
date(date &);
void print(char * msg = "");
};
Можно отметить еще что-то новое: во втором конструкторе
переменные d и y имеют значения по умолчанию, так что если
бы Вы скажете date birthday(12); birthday автоматически бу-
дут заданы значения: d = 1 и y = 88. Вы также можете сказать
date birthday(11,5) или date birthday(12,5,87). Значения по
умолчанию всегда должны быть последними значениями в списке.
Четвертый конструктор называется инициализацией копированием
(copy initializier). Он является специальным и часто выска-
кивает там, где Вы его не ждете. Например, в описании
date celebration=birthday;,
инициализация копированием вызывается автоматически, если
даже оператор и не выглядит как вызов этого конструктора ко-
торый должен бы появиться как date celebration(birthday);)
Отсутствие инициализации копированием часто является при-
чиной проблем у начинающих. Она настолько важна, что следую-
щее определение C++ фирмы AT&T будет автоматически генериро-
вать инициализацию копированием, если только Вы не написали
ее сами. Теперь рассмотрим код для класса date.
#include "date.hpp"
#include
#include /* для atoi() */
date::date() {
struct tm *t;
time_t Ltime;
time(&Ltime);
t = localtime(&Ltime);
month = t->tm_mon+1;
day = t->tm_day;
year = t->tm_year;
}
date::date(int m, int d, int y) {
/* отмечаем, что мы задали значения
по умолчанию лишь в объявлении класса */
month = m; day = d; year = y;
}
date::date(char* datestring) {
char buf[10]; /* временный буфер для кусков */
/* преобразует до тех пор, пока не
разделитель */
char * dt = datestring; char *bf = buf;
month = atoi(dt);
while(*dt != '/' && *dt != ':') dt++;
dt++; /* движемся до '/' или ':' */
day = atoi(dt);
while(*dt != '/' && *dt != ':') dt++;
dt++;
year = atoi(dt);
}
date::date(date & otherdate)
{
/* инициализация копированием */
month = otherdate.month;
day = otherdate.day;
year = otherdate.year;
}
void date::print(char * msg) {
cout <
clase tuit {
int a, b, c;
public:
tuit(int i=0, int j = 0, int k = 0)
{ a=i; b = j; c = k; }
/* см. "открытые функции" */
tuit(tuit &); /* инициализация копиpованием */
tuit operator+(tuit &);
tuit operator-(tuit &);
tuit operator=(tuit &);
void print(char * name = "");
};
tuit::tuit( tuit & othertuit) {
a = othertuit.a; b = othertuit.b; c = othertuit.c;
}
tuit tuit::operator+(tuit & arg) {
tuit result;
result.a = a + arg.a;
result.b = b + arg.b;
result.c = c + arg.c;
return result;
}
tuit tuit::operator-(tuit & arg) {
tuit result;
result.a = a - arg.a;
result.b = b - arg.b;
result.c = c - arg.c;
return result;
}
tuit tuit::operator=(tuit & rvalue) {
a = rvalue.a;
b = rvalue.b;
c = rvalue.c;
return *this;
}
void tuit::print(char * name) {
cout << name << ":";
cout << "a = " << a << ", b = " << b <<
", c = " << c << "\n";
}
main() {
tuit x(1,2,3), y(10), z(11,12);
tuit u = x + y - z;
/* прелестно просто, не так ли? */
x.print("x"); y.print("y"); z.print("z");
(x+y).print(x+y);
(x+y-z).print("x+y-z");
u.print("u");
}
В этом примере имеются два места, которые могут поставить
Вас в тупик: использование '&' и ключевого слова this.
Смысл '&', по сути дела, тот же, что и в C: "адрес чего-то".
Вы можете использовать его, как могли бы делать это в C
(если у Вас есть int c, то Вы можете получить адрес c, ска-
зав &c). Однако, в C++ использование '&' расширено - в при-
мере оно называется ссылкой (reference). Значения поставля-
ются функциям и возвращаются функциями "по ссылке". Это оз-
начает: "Я передаю тебе значение, преврати его в адрес".
Передача по ссылке часто предпочтительна при передаче пара-
метров и возврате значений; обычно она повышает эффектив-
ность.
Ключевое слово this означает "адрес объекта, в котором я
нахожусь". Функции члены легко могут выбирать любой элемент
объекта просто по имени элемента, но this необходимо для
получения адреса объекта. При совместном использовании опе-
раций всегда важно вернуть значение. В случае operator+() и
operator-() оно совершенно очевидно (результат операции),
но не является таким очевидным в некоторых других случаях,
подобных operator++() или operator=().
Чтобы решить эту небольшую дилемму, помните, что Вы долж-
ны уметь использовать операции в выражениях, подобных
if (A++) и A=B=C. Поэтому результатом операции должен быть
сам объект: *this. Отметим, что адрес /this/ должен быть
разименован до возврата результата; функция объявлялась как
возвращающая ссылку, и ссылка "ожидает", чтобы ей дали
объект, а не адрес объекта.
Создание нового типа из старого типа
Здесь Вы можете подумать, что требуется изрядно порабо-
тать при создании нового типа. Так оно и есть, ко времени,
когда Вы добавляли операции, а также все другие хитрые воз-
можности. Но такая концентрация усилий окупается двумя
путями:
1. Получив однажды новый тип как отлаженный, Вы
всегда работаете с ним. Его легко использовать в
Вашей конечной системе, потому что компилятор га-
рантирует правильность интерфейса и то, что Вы
используете его надлежащим образом.
2. Имея однажды созданный работающий тип, Вы можете
унаследовать его в новых типах. Вы можете сделать
небольшую или очень большую модификацию для сво-
его нового типа, но все же большая часть работы
уже проделана.
Посмотрим, как это работает при наследовании из класса
OriginalWork. Построим класс для более специфичной творчес-
кой работы:
#include "owork.hpp" /* объявляем базовый класс */
class Painting : public OriginalWork {
/* наследует базовый класс */
char style[30]; /* добавляем некоторые новые члены */
char owner[30];
public:
Painting(char * artist, char * title, char * sty,
char *own, int m, int d, int y, int val);
void information(); /* говорит нам о картине */
};
Единственное различие между Painting (Живопись) и обыкно-
венным определением класса - это "public: OriginalWork",
которое говорит: "этот новый тип данных создан из
OriginalWork". public позволяет производному (Coderived)
классу Painting иметь доступ ко всем public элементам базо-
вого класса OriginalWork. Теперь определим функции члены:
#include "painting.hpp" /* где находится объявление */
Painting::Painting(char * artist, char * title,
char * style, char * owner, int m,
int d, int y, int val)
: (artist, title, m, d, y, val) {
strcpy(style,sty);
strcpy(owner,own);
}
void Painting::information() {
cout << "Painting:\n";
print();
cout << "Style : " << style << "\n";
cout << "Owner : " << owner << "\n";
}
Здесь происходят две мудреные вещи: вызывается конструк-
тор для базового класса и происходит обращение к функции
члену базового класса. Конструктор для базового класса вызы-
вается после имени функции и списка параметров и до открытия
фигурной скобки функции. Это обращение обозначено двоеточием,
подобно тому, как обозначен наследуемый класс в описании
производного класса. Если Ваш базовый класс имеет совместно
используемые конструкторы, то Вы можете вызвать любой из
конструкторов, просто задавая соответствующие параметры.
В Painting::information(), мы вызвали print(), которая явля-
ется функцией-членом класса OriginalWork. Это так просто -
если функция существует в базовом классе, то Вы можете ис-
пользовать ее. Ниже дается кое-что для упражнений с нашим
новым классом:
#include "painting.hpp"
main() {
Painting Bull("Ralph Picasso", "Bull & Doves",
"Abstract Expressionism", "Bend Art Museum",
5,26,88, 495);
Bull.information(); /* обращение к функции-члену */
Bull.print();
/* обращение к функции из базового класса */
}
Чтобы показать, как Вы можете продолжать этот процесс
бесконечно, создадим класс из Painting:
/* Файл CUBIST.HPP */
#include "painting.hpp"
class Cubist : public Painting {
int number_of_eyes; /* ... на одной стороне лица */
public:
Cubist( char * artist, char * title, char * sty,
int eyes, char * own, int m, int d,
int y, int val);
int eyes() { return number_of_eyes; }
};
Cubist::Cubist( char * artist, char * title, char * sty,
int eyes, char * own, int m, int d,
int y, int val)
: (artist, title, sty, own, m, d, y, val) {
number_of_eyes=eyes;
}
#include "cubist.hpp"
main() {
Cubist Only("Bob Dega", "I Only Have Eyes...",
"early", 3, "Bend Art Museum", 1,14,88, 196);
Only.information();
cout << "This was from the "<< Only.eyes()
<< " eye period\n";
}
Вызывать можно конструкторы только непосредственного ба-
зового класса, но не класса, из которого наследован базовый
класс.
eyes() написана как открытая (in-line). Это удобный и
эффективный способ определения очень коротких функций (смот-
ри in-line).
Наконец, а что, если Вы не хотите унаследовать класс, но
имеете объект этого класса в качестве члена структуры Вашего
класса? Например, мы хотим использовать наш класс date для
хранения начала и конца определенного периода творчества
художника. Наследование здесь не работает, так как мы хотим
использовать date дважды. Ответ состоит в использовании
объектов-членов:
#include "cubist.hpp" /* вышеприведенный пример */
#include "date.hpp" /* описание класса "date" */
class CubistPeriod : Cubist {
date beginning;
date end;
public: /* Отметим, как вызываются базовый класс и
конструкторы объектов до левой фигурной скобки */
CubistPeriod(char * artist, char * title, char * sty,
int eyes, char * own, int m, int d, int y,
int val, char * start, char * finish)
: (artist, title, sty, eyesown, m, d, y, val),
beginning(start), end (finish){}
/* Нижеследующая функция, вероятно, больше, чем
следовало бы открытой (in-line) функции: */
void All_info() { information();
cout << "period starts: "; beginning.print();
cout << "period ends: "; end.print();
}
};
main() {
CubistPeriod Dog ("Bob Dega", "Five-legged dog",
"midlle", 2, "Bend Art Museum", 2, 24, 88, 399,
"11/15/87", "2/25/88");
Dog.All_info();
}
Компилятор будет допускать значительное количество непра-
вильного употребления открытых функций, но откажется компи-
лировать, если они окажутся слишком большими или сложными.
Как видите, вызов конструктора для объекта члена класса поч-
ти такой же, как и вызов конструктора для базового класса,
за исключением того, что нужно назвать объект.
По окончании базового курса
Ну, вот Вы и прошли через все препятствия начального
курса по C++. У Вас достаточно образцов для того, чтобы на-
чать писать свои собственные классы. Когда Вы увидите, как
легко это делается в C++, у Вас возникнут новые и более сме-
лые идеи и Вы захотите знать, как делаются вещи, которые мы
Вам еще не показали. Следующая глава открывает более глубо-
кие возможности C++.
Дальнейшая помощь в работе
Как владелец Zortech C++, Вы начнете получать годовую
подписку Zortech C++ Newsletter, как только пришлете свою
регистрацию. Журнал содержит советы по программированию,
разные хитрости и побочные эффекты при пользовании
Zortech C++, а также информацию о новых релизах компилятора,
продуктах на C++ и другие полезные новости по C++.
Если Вы не являетесь владельцем компилятора или Ваша под-
писка закончилась, то Вы можете получить ежегодник, отправив
32 доллара или 15.75 фунтов стерлингов за одногодовую под-
писку шести двухмесячных выпусков по адресу:
Америка Европа
Zortech C++ Newsletter Zortech C++ Newsletter
361 Massachussetts Ave 106-108 Powis St
Arlington MA 02174 London SE18 6LU
Если Вы предложите заметку, которая будет опубликована в
следующем выпуске, то Вы получите годовую подписку и следую-
щую версию компилятора Zortech C++ бесплатно.
БОЛЕЕ СЛОЖНЫЙ C++
ДДДДДДДДДДДДДДДДДДД
Этот раздел описывает некоторые из более глубоких возмож-
ностей языка. Изложение материала не следует рассматривать
как полный справочник, оно достаточно лишь для ознакомления.
Дальнейшие подробности можно найти, например, в книгах
Винера и Пинсона или Страустрапа.
Вызов функций-членов
Как видно из предыдущего, если Вы имеете объект OBJ и хо-
тите вызвать одну из его функций-членов func(), Вы просто
говорите OBJ.func(). Что, если Вы определяете функцию-член
класса и хотите вызвать другую функцию-член класса? Когда Вы
находитесь внутри функции-члена, всегда предполагается, что
Вы работаете с объектом, который еще не имеет имени - имено-
вание не появляется до тех пор, пока объект не объявляется.
Для вызова функции-члена класса из другой функции-члена
просто вызовите эту функцию без указания объекта, связанного
с ней, т.е.: func().
Константы
Для создания константных значений в обычном C Вы исполь-
зовали препроцессор, например: #define A 10. К сожалению,
когда препроцессор завершается, заменяя каждое вхождение
A на 10, компилятор не имеет записи об A и не может выдать
Вам какого-либо сообщения с идентификатором A, что значи-
тельно осложняет отладку программы.
C++ включает понятие константы (const), const застав-
ляет компилятор контролировать и запрещать любую возможную
модификацию значения. В приведенном выше случае: const
int A=10. Константы намного более гибкое средство, чем опе-
ратор #define; они понимают 'область действия' ('scoping',
смотрите раздел 'Область действия'), можно объявить
объект-константу или передать константные параметры функци-
ям. Zortech C++ транслятор может улучшить порождаемый код,
если он знает, что нечто является константой.
Комментарии
C++ имеет два типа комментариев: обычный комментарий
C /* и */ и новый тип комментария, который продолжается до
конца строки:
int a = 4; //комментарий только до конца этой строки
Многократные включения файлов-заголовков
Всякий раз, когда Вы используете класс, необходимо вклю-
чать файл заголовков, который объявляет этот класс. Так как
некоторые классы порождают или используют другие классы,
файлы заголовков из одного класса могут включать в себя фай-
лы заголовков из другого класса и Вы можете оказаться в не-
допустимой ситуации, когда один и тот же самый файл заголов-
ков включается более одного раза. Компилятор не допускает
повторного объявления того же самого класса и сообщает об
этом как об ошибке.
Общепринятым для предотвращения объявления класса более
одного раза является использование препроцессора. Это реа-
лизуется созданием специальной переменной препроцессора для
каждого включаемого файла. В качестве имени переменной ис-
пользуется имя файла, все буквы которого заглавные и не со-
держат символа '.' (ANSI C не разрешает использование симво-
ла '.' в именах переменных). Посмотрите пример для файла
"CHAIR.HPP":
#ifndef CHAIRHPP
#define CHAIRHPP
class chair { // объявление класса chair
};
#endif CHAIRHPP
Объявление класса chair включается только, если перемен-
ная CHAIRHPP не была ранее определена.
Область действия
Правила области действия (scoping rules) определяют части
программы, где переменная действительна. Эти части разделя-
ются открывающей и закрывающей фигурными скобками ({ и }).
Чтобы увидеть, когда переменная выходит из области дейст-
вия (становится недействительной), найдите ближайшую фигур-
ную открывающую скобку перед объявлением этой переменной и
затем найдите соответствующую ей закрывающую скобку. Пере-
менная выходит из области действия после прохождения
/при исполнении/ закрывающей скобки. Если переменная являет-
ся объектом некоторого класса, то при выходе из области
действия будет вызван ее деструктор (если таковой определен).
В обычном C все переменные должны быть объявлены в начале
области действия, сразу после открывающей скобки и перед лю-
бым оператором. В C++ Вы можете объявлять переменные в месте
их использования. Подходящим примером служит счетчик цикла
for :
...
for (int i = 0; i<100; i++)
for (int j = 0; j<100; j++)
// здесь выполняется работа
Заметьте, что можно объявлять и инициализировать пере-
менную одновременно.
Открытые (inline) функции
Существует много ситуаций, когда Вам нужно скрыть некото-
рую сложность программирования путем упрятывания небольшой
части программы в вызов функции (это также позволит Вам ис-
пользовать имя, которое может сделать более осмысленным чте-
ние программы). К сожалению, вызовы функций ведут к опреде-
ленным накладным расходам, что часто является нежелательным.
C++ объединяет лучшее из двух подходов при помощи откры-
тых функций. Объявляя функцию открытой, Вы заставляете ком-
пилятор заменить все вызовы функций кодом открытой функции
(как если бы Вы использовали препроцессор).
Открытые функции обычно считаются единственными 'приемле-
мыми' определениями для появления в файлах заголовков. Они
должны быть краткими. Открытые функции C++ должны использо-
ваться в местах, где в обычном C использовались операторы
#define для замены небольшой части кода. Примеры будут в
следующем параграфе.
Функции доступа
Обычно данные, составляющие объект некоторого класса,
объявляются как 'приватные' (private); это означает, что Вы
не можете извлечь их и испортить за исключением случая, ког-
да программист специальным образом дает Вам на это разреше-
ние (т.е. Вы должны использовать функции члены класса или
функции 'друзья'). Часто, однако, Вам нужно прочитать конк-
ретные значения из объекта. Вместо того, чтобы делать эти
значения общими (что означает, что любой может их изменить),
лучше написать функции доступа, которые возвращают значение,
но не допускают изменения извне этого значения в объекте.
Функции доступа являются, возможно, наиболее распространен-
ным использованием открытого кода.
Пример:
#include // теперь можно использовать поток
class insect {
int legs;
int eyes;
int flight;
public: // все описанное выше приватно
// открытый конструктор
insect(int l, int e, int f)
{legs=l; eyes=e; flight=f;}
// несколько открытых функций доступа
int number_of_legs() {return legs;}
int number_of_eyes() {return eyes;}
int does_it_fly() {return flight;}
};
main() {
insect bug(7,9,1);
cout << bug.does_it_fly();
}
Заметьте, что Вам не нужно объявлять функцию откры-
той, если она является частью объявления класса;
это подразумевается автоматически.
Динамическое распределение памяти
Имеется два способа получения памяти в C++. При объявле-
нии переменных им отводится место в стеке, продвижением вниз
указателя стека. Когда переменные выходят за область опреде-
ления, память из-под них освобождается автоматически, движе-
нием вверх указателя стека. Размер размещаемой в стеке памя-
ти должен всегда быть известен во время компиляции. Если
нужно создать переменную, размер которой неизвестен при ком-
пиляции, следует в программе позаботиться об отведении этой
памяти в куче (heap), называемой также свободной памятью
(free store). Кучу можно представлять как занимающую дно
пространства памяти программы и растущую вверх, в то время
как стек занимает вершину и растет вниз.
Можно занимать и освобождать память в куче в любой точке
программы. Важно понять, что размещаемая в куче память не
подчиняется правилам области определения, в отличие от дру-
гих переменных (это полезная возможность - смотрите параграф
Ссылки). Эти переменные никогда не оказываются вне области
определения. Так что заняв память в куче, следует самому по-
заботиться о ее освобождении. Если продолжать занимать
память в куче, не освобождая ее, то программа (мистическим
образом) сломается. Большинство C пакетов имеют библиотечные
функции (например, malloc(), free()), обеспечивающие работу
с динамическим отведением памяти, но в C++ она, как доста-
точно важная, является частью языка. C++ использует опера-
ции new и delete для отведения и освобождения динамической
памяти. Аргумент new - выражение, задающее число байтов в
отводимой памяти (Это выражение состоит из имени типа и,
возможно, следующего за ним в квадратных скобках числа: чис-
ла элементов этого типа, которые нужно разместить.); возвра-
щаемое значение - указатель на начало блока памяти. Аргумен-
том delete является начальный адрес блока памяти, которую
нужно освобождать (тот самый адрес, который был ранее пос-
тавлен new). Предположим, мы хотим, имея некоторые целые x
и y, создать матрицу из x на y плавающих чисел (float);
тогда
float * mat = new float[x*y];
разместит такую матрицу, а
delete mat;
освободит память. Можно продолжать использование памяти пос-
ле ее освобождения или освободить ее более одного раза - оба
варианта являются ошибочными и могут приводить к трудно об-
наруживаемым ошибкам.
Конструкторы и деструкторы
Любой тип данных может быть инициализирован определенными
способами, что выполняется при исполнении его описания, и
может быть очищен, когда управление покидает его область оп-
ределения. Когда в C++ создаются новые типы данных, эти ини-
циализация и очищение выполняются посредством конструкторов
и деструкторов.
Компилятор автоматически ставит обращение к соответствую-
щему конструктору при исполнении описания и к деструктору -
при выходе объекта из своей области определения.
Примеры инициализации включают установку переменных в
известные значения, отведение памяти в куче, копирование
значений из другого объекта и более необычные работы, свя-
занные со своеобразием типов, которые можно создать на C++
(например, рисование окна, очищение очереди или инициализа-
ция последовательного порта). Примерами очищения могут слу-
жить возврат памяти в куче, удаление окна с экрана и т.п.
Для каждого класса может быть несколько конструкторов
(отличающихся списками параметров) но только один деструк-
тор. Деструкторы не имеют параметров. Конструкторы имеют то
же имя, что и класс. Имя деструктора начинается с тильды (~),
за которой следует имя класса. Вот несколько примеров объяв-
лений конструкторов и деструктора:
class matrix { //данные матрицы
public:
matrix(); /* без параметров */
matrix(matrix &); /* инициализация копированием */
matrix(int i, int j, int a);
matrix(int i, int j, float a);
~matrix(); /* деструктор */
// другие объявления класса matrix
};
Для простых классов конструкторы и деструкторы не всегда
необходимы. Если класс базируется на стеке (нет памяти,
отводимой в куче), не требует инициализации переменных и
передается функциям только по ссылке (передача по значению
требует инициализации копированием), то конструктор, вероят-
но, не нужен.
Код конструкторов и деструкторов такой же, как и у других
функций членов, за небольшими исключениями. Конструктор
автоматически возвращает this (указатель на объект; через
этот указатель программируется инициализация и присваивание),
а деструктор не возвращает никакого значения. Не следует
указывать никакого возвращаемого значения ни в объявлениях
внутри класса, ни в описаниях этих функций.
Обычно, когда объект создается, сначала отводится память
под все размещаемые в стеке переменные, а затем вызывается
конструктор (наоборот, при выходе за область определения
сначала вызывается деструктор, если таковой был определен, а
затем освобождается память стека). Если, однако, Вы выполни-
ли в конструкторе присваивание переменной this, автоматичес-
кое отведение памяти в стеке подавляется (Вы должны понимать,
что делаете, прежде чем попробуете этот прием).
Ссылки
Ссылка - это указатель, который выглядит как объект.
Компилятор сам разыменовывает его (применяя операцию *).
Можно инициализировать ссылку другим обектом (в этом случае
у Вас появится два способа работы с одним и тем же объектом,
что само по себе порождает проблемы и должно использоваться
с осторожностью). Вот пример:
foo A(); // создается "foo"
foo & B = A;
// создается ссылка типа "foo", инициализированная A
A.function(); // это то же самое, что и
B.function();
В вышеприведенном фрагменте кода, когда A выходит за об-
ласть определения, для нее вызывается деструктор. Поскольку
B является ссылкой, для нее деструктор не вызывается никогда.
Тот факт, что правило области определения /в части вызова
деструктора/ подавляется для ссылок, может быть полезен.
Второй путь использования ссылок - создать объект полностью
в свободной памяти и работать с ним через ссылку. Большинст-
во объектов располагается в стеке, кроме тех их частей, кото-
рые явно создаются при помощи new. Однако, можно создавать
эти объекты так, чтобы они целиком размещались в свободной
памяти (куче). Хороший пример - объекты данных, хранящиеся в
бинарном дереве. Вообще говоря, не хотелось бы, чтобы куски
дерева разрушались просто от того, что они выходят за грани-
цы области определения. Необходим полный контроль над тем,
когда они добавляются к дереву и убираются из дерева. В ка-
честве иллюстрации рассмотрим функции add() и remove() в
гипотетическом классе бинарных деревьев BinaryTree:
void BinaryTree::add(int data) {
// "leaf"(лист) есть некоторый класс, содержащий
// данные и "прикрепляемый" к этому бинарному дереву
leaf & newleaf = *new leaf(data);
// Поскольку ссылка на нечто выглядит так же, как и
// это нечто, а не как указатель на него, мы должны
// разыменовать указатель, поставляемый операцией
// new, сказав *new
attach(newleaf);
}
void BinaryTree::remove(leaf & lf) {
// "un_attach" удаляет "лист" из бинарного дерева и
// возвращает ссылку на лист:
leaf & oldleaf = un_attach(lf);
// для удаления ссылки (т.е. вызова деструктора для
// ссылки) следует привести ее к указателю:
delete (leaf *)(&oldleaf);
}
Заметьте, что не обязательно использовать ссылку при соз-
дании объекта в свободной памяти - можно просто использовать
указатель, и генерируемый компилятором код будет тем же.
Единственная разница - в том, как выглядит код; получающиеся
объекты в любом случае не подвержены правилам области опре-
деления.
Использование ссылок в вышеприведенной манере или как
дублирующее указатели на объект может приводить к изощренным
ошибкам; его следует избегать или как следует понять, почему
этот способ необходим Вам в том или ином случае. Наиболее
распространенное использование ссылок - передача параметров
функциям. Если Вы объявили для функции передачу по ссылке,
указатель (представляющий ссылку) всегда передается незави-
симо от синтаксиса конкретного вызова функции. Например:
void fred(foo & A) { A.member_function();} //используем А
main() {
foo B;
fred(B); fred(&B); // вызовы идентичны
}
Если функция не модифицирует своих параметров, передача
по ссылке предпочтительна как наиболее эффективный метод.
Это также простейший способ действий для начинающих. Если по
некоторым причинам Вам нужно модифицировать параметры (вмес-
то того, чтобы просто скопировать их в локальные переменные
и модифицировать там), используйте передачу по значению.
В этом случае компилятор создает копию исходного объекта
(используя инициализацию копированием, которую Вы должны на-
писать). Это еще один непростой подход, которого начинающему
следует избегать.
Последний прием с использованием ссылок - обойти механизм
защиты информации при помощи функции доступа, возвращающей
ссылку на фактическое значение, а не копию этого значения.
Примером того, где это полезно, является класс vector, в ко-
тором пользователь может изменить элемент вектора при помощи
операции [].
#include
class ten_vector{
int element[10];
public;
ten_vector(int x = 0) { /* значение по умолчанию */
for(int i = 0; i < 10; i++)
element[i] = x;
}
int value(int i) { if (i < 10) return element[i];
else return 0; }
int & operator[](int i) { return element[i]; }
};
main() {
ten_vector V;
cout << V.value(5);
/* можно читать, но не изменять его */
V[5] = 20; /* используется "operator[]" */
cout << " " << V.value(5);
}
Заметьте, как симпатично это работает - поскольку компи-
лятор разыменовывает адрес, который поставляет operator[],
строка V[5]=20 читается совершенно естественно. Возврат
объекта из функции может оказаться непростым делом (смотрите
следующий параграф). В частности, нельзя пытаться возвратить
ссылку на локальную переменную (называемую также автомати-
ческой переменной). Локальные переменные размещаются в сте-
ке - когда функция завершится, она возвратит ссылку на пе-
ременную вне области определения!
Совместное использование операций (Operator Overloading)
Почти все операции в C++ могут совместно использоваться в
различных смыслах в зависимости от типов данных, к которым
они применяются. Чтобы правильно работать с совместно ис-
пользуемыми операциями, надо понимать следующее.
* При передаче аргументов в функции - операции следует
использовать ссылки, и аргументы никогда не должны
модифицироваться (Вы же не ожидаете, что A + B будет
модифицировать A или B, не так ли?).
* Хотя разрешается совместно используемые операции
описывать как функции-друзья (friends) с двумя пара-
метрами, предпочтительнее (и менее запутанно) - де-
дать их функциями-членами с одним параметром. Для
бинарных операций this при этом будет указывать на
объект - левый операнд, а параметр - задавать правый
операнд.
* При возвращении объекта из функции-операции (или
другой функции, используемой в этом плане) возврат
следует выполнять значением. Это значит, что должен
быть конструктор для инициализации копированием; в
случае, когда объекты имеют части в куче, это должно
быть запрограммировано особенно тщательно, чтобы из-
бежать порождения мусора (исключительно работоспо-
собный метод, позволяющий избежать мусора, - подсчет
ссылок, он демонстрируется в классе String в книге
Строуструпа на странице 184).
* При совместном использовании операций следите за тем,
как они работают в выражениях произвольной сложности
(A+B-C/D...). Пользователь, без сомнения, попытается
сделать что-нибудь, о чем Вы и не думали.
Операция присваивания (operator=())
Функция operator= по ряду причин необычна. В простом C
присваивание возвращает присваиваемое значение, благодаря
чему возможны выражения вроде A=B=C, но не для структур.
Неприятие в реализации не допускало множественное присваива-
ние структур. C++ вылечил эту болезнь, так что возвращение
объекта после присваивания (при помощи оператора return
*this) допускает множественное присваивание объектов.
Функция operator= не всегда используется там, где Вы это-
го ожидаете. Например:
/* файл potato.hpp */
class potato {
int u, v;
public;
potato (int a, int b = 0) { u = a; v = b; }
potato (potato & p) { u = p.u; v = p.v; }
potato operator=(potato & p)
{ u = p.u; v = p.v; return *this; }
};
// файл potatst.hpp
#include "potato.hpp"
main() {
potato X(1,2);
potato y = potato(3,4); // вызывается potato(3,4)
potato Z = 5; // вызывается potato(5,0)
potato Q = X; // вызывается potato(potato &)
Y = Z; // вызывается potato::operator=(potato &)
}
Обратите внимание на использование *this в функции
operator=(). Поскольку operator= возвращает значение типа
potato, код return *this означает "возврати копию самого
себя".
Наконец, при создании производного класса operator=() не
наследуется как все другие функции - она должна определяться
заново для каждого нового произвольного класса. Часто хочет-
ся использовать operator=() из базового класса, не набирая
ее заново.
Вот как это сделать:
#include "potato.hpp"
class tomato : public potato {
int t;
public:
tomato(int a, int b, int c) : (a,b) { t = c;}
// заметьте, как вызывается инициализация копированием
// из базового класса:
tomato(tomato & rv) : (rv) { t = rv.t; }
tomato operator=(tomato & x) {
t = x.t;
(potato)(*this) = (potato)x;
return *this;
}
};
main() {
tomato A(1,2,3), B(4,5,6);
A = B;
}
Указатели на void
Если объявить указатель на void, он будет содержать 'родо-
вой' адрес, который может быть приведен к адресу объекта лю-
бого типа. Указатели на void используются при передаче ука-
зателей функциям, которые не могут знать тип передаваемого
им объекта, а также для передачи из функций объектов, не
имеющих типа. Оба метода обходят контроль типов; их следует
избегать начинающим.
Виртуальные функции
Виртуальная функция - один из ключевых элементов в C++
как объектно-ориентированном языке. Хотя язык может поддер-
живать абстрактные типы данных и наследование, он не являет-
ся действительно объектно-ориентированным, если отсутствует
общность (commonality), называемая еще "полиморфизм". Вирту-
альные функции являются средством, обеспечивающим общность в
C++.
Если функция объявлена в базовом классе как "обыкновен-
ная" (не виртуальная), она не полиморфная. Если при наследо-
вании из базового класса в новом классе функция будет пере-
определена, получаются две отдельных функции. Если, однако,
функция объявлена в базовом классе как virtual, и переопре-
делена в классах, из него производных, то будет существовать
единственная функция для каждого класса, и функция может
быть вызвана для производного класса из базового класса.
Что это значит? Предположим, мы строим оконную систему,
и существует три типа объектов, которые можно вывести на
экран (назовем их ScreenObj): Dialog (который пользователь
может вводить), Reader (который пользователь может просмат-
ривать) и Message (который выводит сообщение и требует прос-
того ответа да-или-нет). На экране может быть несколько по-
добных объектов и все они управляются программой - менедже-
ром экрана.
Менеджер экрана должен уметь открывать, закрывать, перед-
вигать и перерисовывать все выводимые объекты, независимо от
того, какого они конкретно типа. Чтобы обеспечить это, функ-
ции Open, Close, Move и ReDraw объявляются в базовом клас-
се ScreenObj виртуальными и модифицируются в производных
классах. Менеджер экрана просто хранит список из SreenObj и
вызывает подходящую функцию для каждого элемента списка.
Вот как это могло бы выглядеть:
class SreenObj { // здесь приватные данные
public:
virtual void Open(){} // функции должны иметь определение
virtual void Close(){} // в базовом классе (даже если
// оно пустое)
virtual void ReDraw(){}
virtual void Move(int x, int y) {} // на какое расстояние
// передвигать
};
class Dialog : public ScreenObj {
// здесь приватные данные класса DIALOG
public:
Dialog(); // конструктор
~Dialog(); // деструктор
void Open(); void Close(); void ReDraw();
void Move(int, int);
};
class Reader : public ScreenObj {
// здесь приватные данные класса Reader
public:
Reader();
~Reader();
void Open(); void Close(); void ReDraw();
void Move(int, int);
};
class Message: public ScreenObj {
// здесь приватные данные класса Message
public:
Message();
~Message();
void Open(); void Close(); void ReDraw();
void Move(int, int);
};
// Предполагается, что специализированные для классов
// функции определены где-то еще (эта иллюстрация показы-
// вает лишь схему работы). Они выглядят как обычные эк-
// ранные функции.
class ScreenList { // содержит список из ScreenObj_ектов
struct Window {
ScreenObj * head; // приватная структура
Window * next; }; // чтобы создать связанный список
Window * head; // начало списка
Window * current; // Так мы можем двигаться по списку
public:
void add(ScreenObj &); // добавление к списку
void remove(ScreenObj &); // удаление ScreenObj_екта
void reset() { current = head; }
// переход на начало /списка/
ScreenObj & GetNext();
// возвращает ссылку на очередной ScreenObj из списка
};
main() {
Message M; Reader R; Dialog D;
Screenlist List;
List.add(M); List.add(R); List.add(D);
List.reset();
while ( (ScreenObj & Win = List.GetNext()) != 0)
Win.ReDraw(); // Перерисовать весь список
}
Деструкторы также могут быть объявлены как виртуальные,
что обеспечивает вызов нужного деструктора при работе с про-
изводными классами через базовый класс. Глава 6 книги Винера
и Пинсона посвящена виртуальным функциям.
Друзья (friends)
Часто возникают ситуации, когда необходимо дать функции
не члену класса доступ к приватным элементам структуры клас-
са. Такой доступ может быть разрешен только самим классом, в
котором функция (или, в некоторых случаях, целый класс)
объявляется как friend (друг) внутри объявления класса. Ниже
следует простой пример:
class Integer {
int X;
public:
Integer(int I) : X(I) {};
friend void set(Integer &,int);
};
void set(Integer & A, int J) { A.X = J;}
// не функция член, но имеет доступ к
// приватным данным
Заметьте, что в конструкторе для Integer вызывается кон-
структор для объекта-члена класса X, несмотря на то, что X
есть int (целое), т.е. встроенный тип.
Общие, приватные, защищенные (Public, Private, Protected)
Ключевое слово public (общий, публичный) управляет досту-
пом к данным и функциям членам класса. Public разрешает дос-
туп всем.
Винер & Пинсон обсуждают ключевые слова private и
protected. Они не были частью определения, данного в книге
Строустрапа, и не поддерживались в Zortech C++ в момент пере-
дачи в печать этого руководства. Однако, в будущих версиях
Zortech C++ такая поддержка предполагается. Пожалуйста, про-
верьте файл read.me на втором дистрибутивном диске для полу-
чения более оперативной информации о новых возможностях.
Статические переменные
В Zortech C++ можно использовать static (статические) и
глобальные объекты. Статические объекты подчиняются тем же
правилам области определения, за исключением того, что дест-
руктор не вызывается во время завершения функции, где описан
объект, и объект не "уходит" в промежутках между вызовами
функции, как это происходит со "стековыми" (автоматическими"
переменными.
Глобальные объекты объявляются вне всех функций и доступ-
ны из всех функций. Конструкторы для статических и глобаль-
ных переменных вызываются до входа в main; деструкторы вызы-
ваются при обращении к exit(), явном либо неявном, т.е. при
возврате из main().
Операция разрешения области действия
Операция разрешения области действия :: позволяет точно ука-
зать, какую функцию нужно вызвать, в случаях, когда есть
несколько вариантов,и умолчание-не тот вариант,что Вам нужен.
При использовании без префикса операция разрешения области
действия выбирает глобальное определение или то, которое
предопределено в языке (а не переопределенное для совместно-
го использования). К примеру, можно переопределить ключевое
слово (операцию) для размещения в куче - new. Чтобы выбрать
"нормальное" определение вместо переопределенного, следует
сказать
::new
Переменные также можно выбирать при помощи операции раз-
решения области действия:
int A = 20;
class deelybob {
int A;
public:
deelybob() { A = ::A;
};
|
|