
- •Л. Б. Бузюков, о. Б. Петрова
- •Учебное пособие
- •Предисловие
- •Глава 1. Введение в язык с
- •1.1. История создания и особенности языка с
- •1.3. Элементы языка с
- •1.3.1. Основные символы
- •1.3.2. Ключевые слова
- •1.3.3. Идентификаторы
- •1.3.4. Константы
- •1.3.5. Лексемы
- •1.3.6. Комментарии
- •Глава 2. Типы данных языка c
- •2.1. Числовые типы данных
- •2.2. Объявление переменных
- •2.3. Данные целого типа
- •2.4. Данные вещественного типа
- •Глава 3. Выражения
- •3.1. Операции
- •3.1.1. Арифметические операции
- •3.1.2. Операция присваивания
- •Глава 4. Составление простейших программ
- •4.1. Препроцессор и его функции
- •4.2. Основные директивы препроцессора
- •4.2.1. Директива include
- •4.2.2. Директива define
- •4.2.3. Директива undef
- •4.3. Структура и правила составления программ
- •4.3.1. Структура функции
- •4.3.2. Функция main()
- •4.3.3. Структура простой программы
- •4.3.4. Правила записи объявлений, операторов и комментариев
- •4.3.5. Пример простейшей программы
- •Глава 5. Средства ввода/вывода
- •5.1. Общие замечания
- •5.2. Функция форматированного вывода printf()
- •5.2.1. Основные форматы
- •5.2.2. Модификации форматов
- •5.3. Функция форматированного ввода scanf()
- •Глава 6. Управляющие операторы
- •6.1. Условные операторы
- •6.1.1. Логические выражения
- •6.1.2. Формы оператора if
- •6.1.3. Оператор выбора switch
- •6.2. Операторы цикла
- •6.2.1. Оператор while
- •6.2.2. Оператор for
- •6.2.3. Оператор do-while
- •6.3. Операторы перехода
- •6.3.1. Оператор break
- •6.3.2. Оператор continue
- •6.3.3. Оператор return
- •6.3.4. Применение оператора goto и меток
- •Глава 7. Функции
- •7.1. Основные понятия
- •7.2. Определение функции
- •7.3. Прототип функции
- •7.4. Вызов функции
- •Глава 8. Классы памяти
- •8.1. Логическаяструктура памяти программы
- •8.2. Особенности классов памяти
- •8.3. Объявления переменных
- •8.4. Объявления функций
- •8.5. Время жизни и область видимости программных объектов
- •8.6. Инициализация глобальных и локальных переменных
- •Глава 9. Указатели
- •9.1. Операция получения адреса
- •9.2. Операции над указателями
- •Глава 10. Массивы
- •10.1. Общие сведения о массивах
- •10.2. Одномерные массивы
- •10.3. Двумерные массивы
- •10.4. Массивы и указатели
- •10.5. Массивы и функции
- •Глава 11. Строки
- •11.1. Представление символьной строки при помощи одномерного массива
- •11.2. Указатель на символьную строку
- •11.3. Ввод/вывод символьных строк
- •11.4. Массивы символьных строк
- •11.5. Функции работы состроками
- •Глава 12. Структуры
- •12.1. Определение структуры
- •12.2. Структуры и функции
- •12.3. Указатели на структуру
- •12.4. Массивы структур
- •12.5. Вложенные структуры
- •12.6. Использование синонима типа
- •12.7. Объединения
- •Глава 13. Файлы
- •13.1. Работа с файлами
- •13.2. Функции ввода/вывода
- •Глава 14. Динамическая память
- •14.1. Распределение памяти
- •14.2. Функции управление памятью
- •Глава 15. Проект
- •15.1. Основы создания проекта
- •15.2. Пример создания проекта
- •Глава 17. Основы объектно-ориентированного программирования
- •17.1. Объектно-ориентированный подход
- •17.3. Конструкторы и деструкторы
- •17.4. Инкапсуляция
- •17.5. Полиморфизм
- •17.6. Наследование
- •17.7. Виды взаимодействия классов
- •17.8. Способы графического представления объектно-ориентированной задачи
- •18.2. Библиотека Win32 api
- •18.3. Библиотека owl
- •18.4. Библиотека vcl
- •18.5. Библиотека clx
- •18.6. Библиотека mfc
- •18.7. Библиотека OpenGl
- •19.3. Создание проекта
- •19.4. Редактирование проекта
- •19.5. Компиляция и выполнение программы
- •19.6. Файловая структура проекта
- •19.7. Создание консольного приложения
- •Глава 20. Разработка приложений для операционных систем windows
- •20.1. Взаимодействие программы и Windows
- •20.2. Компоненты библиотеки Win32 api
- •20.3.Функция WinMain()
- •20.4. Оконная процедура
- •20.5. Структура программы для ос Windows
- •20.6. Ресурсы Windows
- •20.7. Взаимодействие прикладной программы и устройств в Windows
- •Глава 21. Создание приложений для ос windows на основе библиотеки mfc
- •21.1. Обзор классов библиотеки mfc
- •21.2. Класс cString
- •21.3. Класс cFile
- •21.4. Класс cPoint
- •21.5. Класс cRect
- •21.7. Приложение, основанное на диалоге
- •21.8. Использование в приложении элементов управления
- •21.9. Мастер классов mfc ClassWizard
- •21.10. Установка начального значения элементам управления
- •21.11. Элементы управления Picture
- •21.12. Элемент управления Group Box
- •21.13. Элемент управления Radio Button
- •21.14. Элемент управления Check Box
- •21.15. Элемент управления List Box
- •21.16. Создание меню
- •21.17. Приложение с двумя диалоговыми панелями
- •21.18. Приложение sdi
- •21.19. Создание панели инструментов
- •21.20. Приложение mdi
- •21.21. Контекстыустройств в mfc
- •21.22. Графические объекты Windows в mfc
- •21.23. Графические операции в mfc
- •П.1. Основы методологии конструирования программ
- •П.1.1. Основные понятия. Программа и алгоритм
- •П.1.2. Этапы разработки программ
- •П.2. Алгоритмы
- •П.2.1. Алгоритм и его свойства
- •П.2.2. Способы описания алгоритмов
- •П.2.3. Средства графического изображения алгоритмов Схемы алгоритмов
- •Псевдокоды
- •Структурограммы
- •П.3. Основные приемы программирования
- •П.3.1. Разновидности структур программирования
- •П.3.2. Программирование линейных и разветвляющихся процессов
- •П.3.3. Программирование циклических процессов
- •Арифметический цикл (цикл с параметром)
- •Итерационный цикл
- •Вложенный цикл
- •Литература
15.2. Пример создания проекта
Необходимо вычислить значение функции y=sin(x)+0,5. Значение x вводится с клавиатуры. Вычисления организовать с помощью функции, которую поместить в отдельный модуль.
Рассмотрим пример простейшего проекта, состоящего из двух файлов с расширением cpp и одного файла с расширением h. Для определенности проект назовем MyProj.
Функция main() будет расположена в файле MyProj.cpp, функция f(), вычисляющая значение у – в файле Modul.cpp, а прототип функции f() – в заголовочном файле Modul.h (обе части модуля имеют одно имя).
При создании программы из нескольких модулей следует соблюдать принцип независимой компиляции модулей. Этот принцип заключается в том, что при подготовке исполняемого файла сначала надо добиться компиляции каждого модуля независимо от других модулей. Отсутствие синтаксических ошибок во всех модулях проекта – необходимое условие для создания исполняемого файла, но недостаточное, так как ошибки могут появиться при объединении модулей, и пока они не будут исправлены, исполняемый файл не получить.
Следующий текст удовлетворяет принципу независимой компиляции модулей и решает поставленную задачу:
Файл MyProj.cpp
#include <stdio.h>
#include "Modul.h"
int main()
{
float y,x;
scanf("%f",&x);
y=f(x);
printf("y=%f\n",y);
return 0;
}
Файл Modul.h
float f(float);
Файл Modul.cpp
#include "Modul.h"
#include <math.h>
float f(float x)
{
float z1;
z1=sin(x)+0.5;
return (z1);
}
Проект можно представить графически (рис. 15.1) с помощью диаграммы модулей (файлов). Каждый файл на этой диаграмме изображается в виде прямоугольника, между прямоугольниками линиями со стрелками показаны связи файлов, которые соответствуют директиве include. Стрелки направлены от зависимого файла к независимому. Независимым файлом обычно бывает заголовочный файл, а зависимый – файла типа *.c, *.cpp.
Рис. 15.1. Диаграмма модулей проекта
Рассмотрим пример проекта, использующего внешние (extern) переменные. В модуле mod.cpp используется внешняя переменная a. В файле prog.cpp объявлена как глобальная и инициализирована переменная с таким же именем. Значение глобальной переменной a передается в функцию модуля mod.cpp для обработки. Переменная класса extern может быть объявлена как внутри блока, так и на внешнем уровне.
В нашем примере внешняя переменная a объявлена внутри функции prc():
Файл prog.cpp
#include "mod.h"
int a=5;
int main(void)
{
prc();
return 0;
}
Файл mod.h
void prc(void);
Файл mod.cpp
#include "mod.h"
#include <stdio.h>
void prc(void)
{
extern a;
printf("%d\n",2*a);
}
Внешняя переменная а представляет собой «мостик», по которому данные (значение глобальной переменной a) из модуля prog.cpp передаются в модуль mod.cpp для дальнейшей обработки.
Глава 16. ОТ C к C++
16.1 Основные отличия языка C++ 16.2. Потоковый ввод/вывод в C++ 16.3. Управление памятью в C++ 16.4. Перегрузка функций в C++ 16.5. Пространства имен в C++
16.1 Основные отличия языка C++
Рассмотренные в гл. 1–15 элементы языка входят в подмножество языка C и могут быть откомпилированы при помощи компилятора языка C или C++. Язык C++ имеет множество дополнительных элементов по сравнению с языком C, которые могут быть откомпилированы только компилятором C++[9].
Традиционно программы, написанные на C, имеют расширение *.c, на C++ – *.cpp, и для их компиляции выбирается соответствующий компилятор. Если разработка программы ведется в специальной инструментальной среде, например, в VC++, возможна настройка компилятора для трансляции с языка C или C++.
Основное и принципиальное отличие C++ от C составляют классы, эта составляющая языка рассмотрена в гл. 17. Также в C++ появляются новые элементы языка, такие как объекты-потоки для ввода/вывода данных cin и cout, новые операторы (:: – оператор разрешения области видимости), средства для управления памятью (операторы new и delete), шаблоны, обработка исключений.
16.2. Потоковый ввод/вывод в C++
Ввод/вывод в C++ осуществляется с помощью потоков библиотеки C++, доступных при подключении заголовочного файла iostream.h (в VC++.NET – объекта-заголовка iostream). Поток представляет собой объект какого-либо потокового класса.
Потоковые классы сконструированы на основе базового класса ios:
ios – базовый потоковый класс;
istream – класс входных потоков;
ostraem – класс выходных потоков;
iostream – класс двунаправленных потоков ввода/вывода.
В потоковые классы включены операторы добавления данных в поток << и извлечения данных из потока >>.
На основе класса istream в библиотеке C++ объявлен объект-поток cin, представляющий собой стандартный буферизованный входной поток, связанный обычно с клавиатурой консоли. Извлечение данных из потока имеет следующую форму записи:
int a;
float b;
cin >> a >> b;
где a и b – переменные заданного типа, в которые помещаются данные из потока cin.
В роли разделителей значений в потоке используются пробельные символы (пробел, знак табуляции, перевод строки), поэтому для ввода данных с помощью cin при выполнении программы следует ввести с клавиатуры значения следующими способами:
34 5.78 Enter
или
34 Enter 5.78 Enter
Ввод данных в поток завершается нажатием клавиши Enter. Если количество заполняемых переменных меньше, чем количество значений в потоке, из потока извлекается столько значений, сколько переменных надо заполнить, а остальные значения сохраняются в потоке и будут прочитаны при следующем извлечении данных из потока.
На основе класса ostream объявлен объект-поток cout, представляющий собой стандартный буферизованный выходной поток, связанный обычно с дисплеем консоли.
Форма записи добавления данных в поток следующая:
cout << a << b;
при этом значения переменных a и b выводятся на экран без разделителя и в формате, заданном по умолчанию. Перемещение курсора на следующую строку экрана после вывода данных не происходит.
Для перевода курсора на новую строку используется манипулятор endl:
cout << a <<" "<< b << endl;
В этом примере значения переменных a и b на экране разделены пробелом, после вывода данных происходит переход на новую строку, а сами значения выводятся на экран в виде, соответствующем их типу: 34 5.78.
Для потока cin определен специальный метод для ввода символов – getline(Str,Count), позволяющий в строковую переменную Str ввести из потока заданное количество символов (Count−1):
char str1[128];
cout <<"STR1-->";
cin.getline(str1,9);
cout << str1 << endl;
Если при выполнении этого фрагмента программы ввести с клавиатуры последовательность символов abcdefghj, в переменную str1 будут помещены 8 символов и символ '\0', а на экране появится строка abcdefgh.
В потоках cin и cout можно форматировать данные, для этого используются специальные манипуляторы, доступные через заголовочный файл iomanip.h.
Пример
Форматирование вывода в потоке cout:
#include <iostream.h>
#include <iomanip.h>
int main(void)
{
//Выравнивание по левому краю – left, по правому краю – right
cout.setf(ios_base::left);
//Вывод с плавающей точкой – scientific, с фиксированной – fixed
cout.setf(ios_base::scientific);
//Точность вывода числа на экране
cout << setprecision(3);
double x=2.5,y=125.76435;
//Ширина поля вывода числа – 15 знаков
cout << setw(15) << x << setw(15) << y << endl;
return 0;
}
Ответ на экране
2 |
. |
5 |
0 |
0 |
e |
+ |
0 |
0 |
0 |
|
|
|
|
|
1 |
. |
2 |
5 |
8 |
e |
+ |
0 |
0 |
2 |
|
|
|
|
|
16.3. Управлениепамятью в C++
Для создания динамических переменных (гл. 14) в языке C++ используются специальные операторы new и delete. Существуют две формы операторов: для одиночной переменной и массива значений.
Оператор new выделяет область памяти для одиночной переменной, размер которой соответствует ее типу, и возвращает указатель того же типа, так что дополнительных преобразований типа указателя не требуется:
float * ptr;
ptr=new float;
В результате выполнения этого фрагмента программы в динамической памяти будет выделена область размером 4 байта для хранения одного значения типа float, и адрес этой области записан в переменную ptr.
Для размещения в памяти нескольких значений одного типа (массива) применяется оператор new[]:
float * ptrm;
ptrm=new float[4];
при этом в квадратных скобках указывается количество элементов, для которых выделяется память. В результате выполнения этого фрагмента программы в динамической памяти будет выделена область размером 16 байт для хранения четырех чисел типа float, и адрес этой области записан в переменную ptrm.
Для освобождения динамической памяти, выделенной при помощи new, используется оператор delete.
Для одиночной переменной освобождение памяти имеет следующий вид:
delete ptr;
при этом освобождается область в динамической памяти размером 4 байта.
Для освобождения памяти из-под массива, размещенного с помощью оператора new[], следует использовать следующую форму оператора delete:
delete[] ptrm;
Следует заметить, что недопустимо смешивать формы операторов new и delete: если память выделялась для одиночной переменной (new), то и освобождение должно производиться оператором delete, если в памяти размещался массив (new[]) – для освобождения памяти должен использоваться оператор delete[].
Пример
Использование операторов new и delete для размещения данных в динамической памяти:
char* st;
//Выделение памяти для строки 100 байт
st=new char[100];
//Объявление указателя и выделение памяти
//для переменной типа int
int* ptr1=new int;
//Объявление указателя и выделение памяти
//для массива элементов типа double
double* ptr2=new double[3];
//Ввод данных в переменные
cout << "Введите строку символов (<100) и целое число->";
cin >> st >> *ptr1;
cout << "Введите три вещественных числа->";
for(int i=0;i<3;i++)
cin >> ptr2[i];
cout << "Введено: " << endl;
cout << "Строка " << st << endl;
cout << "Целое " << *ptr1 << endl;
cout << "Массив вещественных чисел" << endl;
for(i=0;i<3;i++)
cout << i << " " << *(ptr2+i) << endl;
//Освобождение памяти для данной переменной
delete[] st;
delete ptr1;
delete[] ptr2;
Если при выполнении программы ввести данные следующим образом:
zxcvbn 456 Enter
2.5 3.6 4.8 Enter,
то на экран будут выведены значения:
Введено:
Строка zxcvbn
Целое 456
Массив вещественных чисел
0 2.5
1 3.6
2 4.8
16.4. Перегрузка функций в C++
В языке C++ в одной программе могут использоваться несколько функций с одним и тем же именем, и каждая из этих функций выполняет свой собственный набор действий. Это называется перегрузкой функций.
Перегрузка функций – это свойство языка C++, позволяющее в программе использовать несколько функций с одинаковыми именами, выполняющих различные действия и имеющих различные списки параметров.
Пример перегруженных функций:
void Message(int);//Вывод кода сообщения об ошибке
void Message(char*);//Вывод текста сообщения об //ошибке
void Message(int Code)
{
cout <<"Код ошибки:" << Code << endl;
}
void Message(char* Msg)
{
cout <<"Ошибка:" << Msg << endl;
}
Вызов перегруженных функций:
int main(void)
{
Message(100);
Message("Деление на нуль!");
return 0;
}
Компилятор при обработке вызова каждой функции сравнивает списки фактических аргументов при вызове функции и наборы формальных параметров в прототипе функции и по их совпадению определяет, какая из перегруженных функций соответствует вызову. В нашем примере вызов функции Message(100) содержит один целочисленный параметр, что соответствует функции, имеющей прототип void Message(int), а вызов Message("Деление на нуль!") совпадает по списку параметров с прототипом функции void Message(char*).
Результат выполнения программы:
100
Деление на нуль!
Следует заметить, что язык C перегрузку функций не поддерживает. Кроме перегрузки функций в C++ применяется перегрузка операторов.
16.5. Пространства имен в C++
Глобальные переменные видны в любых точках программы, начиная с объявления переменной, локальные – только в пределах блока. Существуют и статические переменные, объявленные внутри блока, их область видимости также ограничивается этим блоком (не путайте с временем жизни!).
Язык C++ позволяет ограничить действие имен некоторой областью, специально для этого объявленной. Такая область называется пространством имен и создается с помощью ключевого слова namespace. В пространство имен могут быть включены переменные, функции.
Создается пространство имен на внешнем уровне:
namespace имя
{
объявления членов пространства
}
Например,
namespace smp
{
int count;
void calc();
}
Функции, объявленные в пространстве имен, имеют прямой доступ к другим членам пространства. Для определения функции, принадлежащей пространству имен, используется оператор разрешения области видимости :: (два двоеточия):
void smp::calc()
{
count++;
}
Доступ к членам пространства имен извне возможен двумя способами.
1. При помощи явного указания пространства имен и оператора разрешения области видимости:
smp::calc();
cout << smp::count << endl;
2. При помощи предложения using namespace, включающего данное пространство имен в область видимости текущего блока, что позволяет обращаться к членам пространства без указания имени пространства:
using namespace smp;
calc();
cout << count << endl;
Если предложение using объявлено на внешнем уровне, видимость членов пространства имен становится глобальной.
При появлении языка C++ элементы, объявленные в библиотеке C++, относились к глобальному пространству имен, не имеющему имени. Действующий стандарт языка C++ все эти элементы относит к пространству имен std.
Требования стандарта соблюдены в компиляторе, входящем в состав Microsoft Visual C++.NET, поэтому при разработке программы в этой среде для обращения к потокам cin, cout следует использовать один из приведенных выше способов:
int a;
std::cout <<"Введите число";
std::cin >> a;
std::cout <<"Вы ввели"<<a<<std::endl;
или
using namespace std;
…
int a;
cout <<"Введите число";
cin >> a;
cout <<"Вы ввели"<<a<<endl;