Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СОВРЕМЕННЫЕ МЕТОДЫ ПРОГРАММИРОВАНИЯ.docx
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
797.27 Кб
Скачать

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;