Главная страница

Язык программирования C++. Вводный курс. С для начинающих


Скачать 5.41 Mb.
НазваниеС для начинающих
Дата24.08.2022
Размер5.41 Mb.
Формат файлаpdf
Имя файлаЯзык программирования C++. Вводный курс.pdf
ТипДокументы
#652350
страница2 из 93
1   2   3   4   5   6   7   8   9   ...   93
Часть I
Краткий обзор языка C++
Программы, которые мы пишем, имеют два основных аспекта: набор алгоритмов; набор данных, которыми оперируют.
Эти два аспекта оставались неизменными за всю недолгую историю программирования, зато отношения между ними (парадигма программирования) менялись. .
В процедурной парадигме программирования задача непосредственно моделируется набором алгоритмов. Возьмем, к примеру, систему выдачи книг в библиотеке. В ней реализуются две главные процедуры: процедура выдачи книг и процедура приема книг.
Данные хранятся отдельно и передаются этим процедурам как параметры. К наиболее известным процедурным языкам программирования относятся FORTRAN, C и Pascal.
С++ также поддерживает процедурное программирование. Отдельные процедуры носят в этом языке название функций. В части III рассматривается поддержка, предоставляемая в
С++ процедурной парадигме программирования: функции, шаблоны функций, обобщенные алгоритмы.
В 70-е годы процедурную парадигму стала вытеснять парадигма абстрактных типов
данных (теперь чаще называемая объектным подходом). В рамках этой парадигмы задача моделируется набором абстракций данных. В С++ эти абстракции получили название
классов. Наша библиотечная система могла бы быть представлена как взаимоотношения объектов различных классов, представляющих книги, читателей, даты возврата и т.п.
Алгоритмы, реализуемые каждым классом, называются открытым интерфейсом класса.
Данные “скрыты” внутри объектов класса. Парадигму абстрактных типов данных поддерживают такие языки, как CLU, Ada и Modula-2. В части IV обсуждаются вопросы поддержки этой парадигмы языком С++.
Объектно-ориентированное программирование расширяет парадигму абстрактных типов данных механизмом наследования (повторного использования существующих объектов) и
динамического связывания (повторного использования существующих интерфейсов).
Вводятся отношения тип-подтип. Книга, видеокассета, компакт-диск – все они хранятся в библиотеке, и поэтому могут быть названы подтипами (или подклассами) одного родительского типа, представляющего то, что может храниться в библиотеке. Хотя каждый из классов способен реализовывать свой собственный алгоритм выдачи и возврата, открытый интерфейс для них одинаков. Три наиболее известных языка, поддерживающие объектно-ориентированный подход, – это Simula, Smalltalk и Java. В части V рассматриваются вопросы поддержки парадигмы объектно-ориентированного программирования в С++.
Хотя мы и считаем С++ в основном объектно-ориентированным языком, он поддерживает и процедурную, и объектную парадигму. Преимущество такого подхода в том, что для каждого конкретного случая можно выбрать наилучшее решение. Однако есть и обратная сторона медали: С++ является достаточно громоздким и сложным языком.
В части I мы “пробежимся” по всем основным аспектам С++. Одна из причин такого краткого обзора – желание дать читателю представление об основных возможностях языка, чтобы затем приводить достаточно содержательные примеры. Скажем, мы не будем рассматривать в деталях понятие класса вплоть до главы 13, однако без упоминания о нем наши примеры оказались бы неинтересными и надуманными.

С++ для начинающих
13
Другая причина такого поверхностного, но широкого обзора – эстетическая. Если вы еще не оценили красоту и сложность сонаты Бетховена или живость регтайма Джоплина, вам будет безумно скучно разбираться в отдельных деталях вроде диезов, бемолей, октав и аккордов. Однако, не овладев ими, вы не научитесь музыке. Во многом это справедливо и для программирования. Разбираться в путанице приоритетов операций или правил приведения типов скучно, но совершенно необходимо для овладения С++.
В главе 1 представлены базовые элементы языка: встроенные типы данных, переменные, выражения, инструкции (statements) и функции. Мы увидим минимальную законченную
С++ программу, обсудим вопросы компиляции, коснемся препроцессора и поддержки ввода/вывода.
В главе 2 мы реализуем абстракцию массива – процедурно, объектно, и объектно- ориентированно. Мы сравним нашу реализацию с реализацией, предоставляемой стандартной библиотекой С++, и познакомимся с набором обобщенных алгоритмов стандартной библиотеки. Мы коснемся и таких вещей, как шаблоны, исключения и пространства имен. Фактически, мы представим все особенности языка С++, хотя обсуждение деталей отложим до следующих глав.
Возможно, некоторые читатели сочтут главу 2 трудной для понимания. Материал представляется без подробного объяснения, даются ссылки на последующие разделы. Мы рекомендуем таким читателям не углубляться в эту главу, пропустить ее вовсе или прочитать по диагонали. В главе 3 материал излагается в более традиционной манере.
После этого можно будет вернуться к главе 2.
1.
Начинаем
В этой главе представлены основные элементы языка: встроенные типы данных, определения именованных объектов, выражений и операторов, определение и использование именованных функций. Мы посмотрим на минимальную законченную С++ программу, вкратце коснемся процесса компиляции этой программы, узнаем, что такое препроцессор, и бросим самый первый взгляд на поддержку ввода и вывода. Мы увидим также ряд простых, но законченных С++ программ.
1.1.
Решение задачи
Программы обычно пишутся для того, чтобы решить какую-то конкретную задачу.
Например, книжный магазин ведет запись проданных книг. Регистрируется название книги и издательство, причем запись идет в том порядке, в каком книги продаются.
Каждые две недели владелец магазина вручную подсчитывает количество проданных книг с одинаковым названием и количество проданных книг от каждого издателя. Этот список сортируется по издателям и используется для составления последующего заказа книг. Нас попросили написать программу для автоматизации этой деятельности.
Один из методов решения большой задачи состоит в разбиении ее на ряд задач поменьше.
В идеале, с маленькими задачами легче справиться, а вместе они помогают одолеть большую. Если подзадачи все еще слишком сложны, мы, в свою очередь, разобьем их на еще меньшие, пока каждая из подзадач не будет решена. Такую стратегию называют
пошаговой детализацией или принципом “разделяй и властвуй”. Задача книжного магазина делится на четыре подзадачи:

С++ для начинающих
14
Прочитать файл с записями о продажах.
Подсчитать количество продаж по названиям и по издателям.
Отсортировать записи по издателям.
Вывести результаты.
Решения для подзадач 1, 2 и 4 известны, их не нужно делить на более мелкие подзадачи.
А вот третья подзадача все еще слишком сложна. Будем дробить ее дальше.
3a.
Отсортировать записи по издателям.
3b.
Для каждого издателя отсортировать записи по названиям.
3c.
Сравнить соседние записи в группе каждого издателя. Для каждой одинаковой пары увеличить счетчик для первой записи и удалить вторую.
Эти подзадачи решаются легко. Теперь мы знаем, как решить исходную, большую задачу.
Более того, мы видим, что первоначальный список подзадач был не совсем правильным.
Правильная последовательность действий такова:
Прочитать файл с записями о продажах.
Отсортировать этот файл: сначала по издателям, внутри каждого издателя – по названиям.
Удалить повторяющиеся названия, наращивая счетчик.
Вывести результат в новый файл.
Результирующая последовательность действий называется алгоритмом. Следующий шаг – перевести наш алгоритм на некоторый язык программирования, в нашем случае – на С++.
1.2.
Программа на языке C++
В С++ действие называется выражением, а выражение, заканчивающееся точкой с запятой, – инструкцией. Инструкция – это атомарная часть С++ программы, которой в программе на С++ соответствует предложение естественного языка. Вот примеры инструкций С++: cout << "
значение переменной book_count: " << book_count;
Первая из приведенных инструкций является инструкцией объявления. book_count можно назвать идентификатором, символической переменной (или просто переменной) или объектом. Переменной соответствует область в памяти компьютера, соотнесенная с определенным именем (в данном случае book_count), в которой хранится значение типа
(в нашем случае целого). 0 – это константа. Переменная book_count инициализирована значением 0.
Вторая инструкция – присваивание. Она помещает в область памяти, отведенную переменной book_count
, результат сложения двух других переменных – books_on_shelf и books_on_order. Предполагается, что эти две целочисленные переменные определены где-то ранее в программе и им присвоены некоторые значения. int book_count = 0; book_count = books_on_shelf + books_on_order;

С++ для начинающих
15
Третья инструкция является инструкцией вывода. cout – это выходной поток, направленный на терминал, << – оператор вывода. Эта инструкция выводит в cout – то есть на терминал – сначала символьную константу, заключенную в двойные кавычки
("значение переменной book_count: "), затем значение, содержащееся в области памяти, отведенном под переменную book_count. В результате выполнения данной инструкции мы получим на терминале сообщение: значение переменной book_count: 11273 если значение book_count равно 11273 в данной точке выполнения программы.
Инструкции часто объединяются в именованные группы, называемые функциями. Так, группа инструкций, необходимых для чтения исходного файла, объединена в функцию readIn()
. Аналогичным образом инструкции для выполнения оставшихся подзадач сгруппированы в функции sort(), compact() и print().
В каждой С++ программе должна быть ровно одна функция с именем main(). Вот как может выглядеть эта функция для нашего алгоритма:
}
Исполнение программы начинается с выполнения первой инструкции функции main(), в нашем случае – вызовом функции readIn(). Затем одна за другой исполняются все дальнейшие инструкции, и, выполнив последнюю инструкцию функции main(), программа заканчивает работу.
Функция состоит их четырех частей: типа возвращаемого значения, имени, списка параметров и тела функции. Первые три части составляют прототип функции.
Список параметров заключается в круглые скобки и может содержать ноль или более параметров, разделенных запятыми. Тело функции содержит последовательность исполняемых инструкций и ограничено фигурными скобками.
В нашем примере тело функции main() содержит вызовы функций readIn(), sort(), compact()
и print(). Последней выполняется инструкция return 0;
Инструкция return обеспечивает механизм завершения работы функции. Если оператор return сопровождается некоторым значением (в данном примере 0), это значение становится возвращаемым значением функции. В нашем примере возвращаемое значение
0
говорит об успешном выполнении функции main(). (Стандарт С++ предусматривает, что функция main() возвращает 0 по умолчанию, если оператор return не использован явно.) int main()
{ readIn(); sort(); compact(); print(); return 0;

С++ для начинающих
16
Давайте закончим нашу программу, чтобы ее можно было откомпилировать и выполнить.
Во-первых, мы должны определить функции readIn(), sort(), compact() и print().
Для начала вполне подойдут заглушки: void compact() { cout << "compact()\n"; } void print() { cout << "print ()\n"; }
Тип void используется, чтобы обозначить функцию, которая не возвращает никакого значения. Наши заглушки не производят никаких полезных действий, они только выводят на терминал сообщения о том, что были вызваны. Впоследствии мы заменим их на реальные функции, выполняющие нужную нам работу.
Пошаговый метод написания программ позволяет справляться с неизбежными ошибками.
Попытаться заставить работать сразу всю программу – слишком сложное занятие.
Имя файла с текстом программы, или исходного файла, как правило, состоит из двух частей: собственно имени (например, bookstore) и расширения, записываемого после точки. Расширение, в соответствии с принятыми соглашениями, служит для определения назначения файла. Файл bookstore.h является заголовочным файлом для С или С++ программы. (Необходимо отметить, что стандартные заголовочные файлы С++ являются исключением из правила: у них нет расширения.)
Файл bookstore.c является исходным файлом для нашей С программы. В операционной системе UNIX, где строчные и прописные буквы в именах файлов различаются, расширение .C обозначает исходный текст С++ программы, и в файле bookstore.C располагается исходный текст С++.
В других операционных системах, в частности в DOS, где строчные и прописные буквы не различаются, разные реализации могут использовать разные соглашения для обозначения исходных файлов С++. Чаще всего употребляются расширения .cpp и
.cxx: bookstore.cpp
, bookstore.cxx.
Заголовочные файлы С++ программ также могут иметь разные расширения в разных реализациях (и это одна из причин того, что стандартные заголовочные файлы С++ не имеют расширения). Расширения, используемые в конкретной реализации компилятора
С++, указаны в поставляемой вместе с ним документации.
Итак, создадим текст законченной С++ программы (используя любой текстовый редактор): void readIn() { cout << "readIn()\n"; } void sort() { cout << "sort()\n"; }

С++ для начинающих
17
}
Здесь iostream – стандартный заголовочный файл библиотеки ввода/вывода (обратите внимание: у него нет расширения). Эта библиотека содержит информацию о потоке cout, используемом в нашей программе. #include является директивой препроцессора, заставляющей включить в нашу программу текст из заголовочного файла iostream.
(Директивы препроцессора рассматриваются в разделе 1.3.)
Непосредственно за директивой препроцессора
#include следует инструкция using namespace std;
Эта инструкция называется директивой using. Имена, используемые в стандартной библиотеке С++ (такие, как cout), объявлены в пространстве имен std и невидимы в нашей программе до тех пор, пока мы явно не сделаем их видимыми, для чего и применяется данная директива. (Подробнее о пространстве имен говорится в разделах 2.7 и 8.5.)1
После того как исходный текст программы помещен в файл, скажем prog1.C, мы должны откомпилировать его. В UNIX для этого выполняется следующая команда:
$ CC prog1.C
Здесь $ представляет собой приглашение командной строки. CC – команда вызова компилятора С++, принятая в большинстве UNIX-систем. Команды вызова компилятора могут быть разными в разных системах.
Одной из задач, выполняемых компилятором в процессе обработки исходного файла, является проверка правильности программы. Компилятор не может обнаружить
1 Во время написания этой книги не все компиляторы С++ поддерживали пространства имен. Если ваш компилятор таков, откажитесь от данной директивы. Большинство программ, приводимых нами, используют компиляторы, не поддерживающие пространство имен, поэтому директива using в них отсутствует.
#include using namespace std; void readIn() { cout << "readIn()\n"; } void sort() { cout << "sort()\n"; } void compact() { cout << "compact()\n"; } void print() { cout << "print ()\n"; } int main()
{ readIn(); sort(); compact(); print(); return 0;

С++ для начинающих
18
смысловые ошибки, однако он может найти формальные ошибки в тексте программы.
Существует два типа формальных ошибок: синтаксические ошибки. Программист может допустить “грамматические”, с точки зрения языка С++, ошибки. Например:
} ошибки типизации. С каждой переменной и константой в С++ сопоставлен некоторый тип. Например, число 10 – целого типа. Строка "hello", заключенная в двойные кавычки, имеет символьный тип. Если функция ожидает получить в качестве параметра целое значение, а получает символьную строку, компилятор рассматривает это как ошибку типизации.
Сообщение об ошибке содержит номер строки и краткое описание. Полезно просматривать список ошибок, начиная с первой, потому что одна-единственная ошибка может вызвать цепную реакцию, появление “наведенных” ошибок. Исправление этой единственной ошибки приведет и к исчезновению остальных. После исправления синтаксических ошибок программу нужно перекомпилировать.
После проверки на правильность компилятор переводит исходный текст в объектный код, который может быть понят и исполнен компьютером. Эту фазу работы компилятора называют генерацией кода.
В результате успешной компиляции образуется выполняемый файл. Если запустить выполняемый файл, полученный в результате компиляции нашей программы, на терминале появится следующий текст: print()
В С++ набор основных типов данных – это целый и вещественный числовые типы, символьный тип и логический, или булевский. Каждый тип обозначается своим ключевым словом. Любой объект программы ассоциируется с некоторым типом.
Например: bool found = false; int main( { // ошибка – пропущена ')' readIn(): // ошибка – недопустимый символ ':' sort(); compact(); print(); return 0 // ошибка – пропущен символ ';' readIn() sort() compact() int age = 10; double price = 19.99; char delimiter = ' ';

С++ для начинающих
19
Здесь определены четыре объекта: age, price, delimiter, found, имеющие соответственно типы целый, вещественный с двойной точностью, символьный и логический. Каждый объект инициализирован константой – целым числом 10, вещественным числом 19.99, символом пробела и логическим значением false.
Между основными типами данных может осуществляться неявное преобразование типов.
Если переменной age, имеющей тип int, присвоить константу типа double, например: age = 33.333; то значением переменной age станет целое число 33. (Стандартные преобразования типов, а также общие проблемы преобразования типов рассматриваются в разделе 4.14.)
Стандартная библиотека С++ расширяет базовый набор типов, добавляя к ним такие типы, как строка, комплексное число, вектор, список. Примеры: vector chapter_titles(20);
Здесь current_chapter – объект типа string, инициализированный константой "
Начинаем". Переменная chapter_titles – вектор из 20 элементов строкового типа.
Несколько необычный синтаксис выражения vector сообщает компилятору о необходимости создать вектор, содержащий объекты типа string
. Для того чтобы определить вектор из 20 целых значений, необходимо написать: vector ivec(20);
Никакой язык, никакие стандартные библиотеки не способны обеспечить нас всеми типами данных, которые могут потребоваться. Взамен современные языки программирования предоставляют механизм создания новых типов данных. В С++ для этого служит механизм классов. Все расширенные типы данных из стандартной библиотеки С++, такие как строка, комплексное число, вектор, список, являются классами, написанными на С++. Классами являются и объекты из библиотеки ввода/вывода.
Механизм классов – одна из самых главных особенностей языка С++, и в главе 2 мы рассмотрим его очень подробно.
1   2   3   4   5   6   7   8   9   ...   93


написать администратору сайта