Содержание:
Теория
Стандартные функции
Математические функции объявлены с включением библиотеки <cmath>
:
#include <cmath> abs(x); floor(x); sin(x); pow(x, y); sqrt(x); |
Пользовательские функции
пример 1:
//... int abs(int x) { return x > 0 ? x : -x; // выход из функции } int main() { cout << abs(-35); // 35 system("pause"); return 0; } |
Функция abs
возвращает целочисленное значение по модулю и имеет единственный целочисленный параметр x
.
пример 2:
//... void print(int i) { cout << "значение = " << i; } int main() { print(40); system("pause"); return 0; } |
Функция print
не возвращает никакого значения и имеет единственный целочисленный параметр i
. Мы можем назвать это процедурой (потому что она не возвращает значение).
Инкапсуляция
В C++ данные и функции разделены на две отдельные группы с уровнем доступа: public и private.
Уровень определяет доступ, который «клиентский код» имеет к данным или функциям:
- Доступ к объектам с уровнем доступа Public можно получить из клиентского кода.
- Доступ к объектам с уровнем доступа Private получить из клиентского кода невозможно (доступ только из самих функций).
В C++ объявление функций (в файле .h
) отделены от ее реализации (в файл .cpp
).
Многофайловая компоновка
Для создания приложения обычно требуется создать 3 файла: файл заголовка (.h
), файл реализации (.cpp
) и основной файл (.cpp
).
- Заголовочный файл (
.h
) определяет интерфейс к функциям, то есть объявление(я) функции(й). - Файл реализации
.cpp
содержит всю логику функций или методов (то есть тело функций). Кроме того, здесь должен быть включен файл заголовка.h
. - Основной файл
.cpp
содержит функциюmain
— так называемая «точка входа», с которой осуществляется запуск программ на C++, и сюда также необходимо включить заголовочный файл.h
.
Рассмотрим на примере (три файла одного и того же приложения):
Пример заголовочного файла (tasks.h):
#ifndef TASKS_H #define TASKS_H //вычисляет периметр треугольника double perimeter(double, double, double); #endif TASKS_H |
Пример файла реализации (.cpp):
#include "tasks.h" //вычисляет периметр треугольника double perimeter(double a, double b, double c) { //операторы } |
Пример главного файла (.cpp):
#include <iostream> #include "tasks.h" using namespace std; void main() { //запросить у пользователя ввод данных //вызов функции //вывод результатов system("pause"); } |
Файлы .cpp
запрашивают подключение различных файлов заголовков.
После чего файл cpp
со всем дополнительным включенным содержимым будет скомпилирован в объектный файл (имеет расширение .o
, то есть объектный файл). Каждый файл cpp компилируется в объектный файл отдельно .
Лабораторные работы
Выполнить: Создайте приложение для нахождения объема и площади поверхности куба. Дана длина стороны куба (она вводится).
Примечание: Необходимо представить три решения: 1) Без пользовательских функций и без многофайлового приложения. 2) С пользовательскими функциями, но без многофайлового приложения. 3) Создание многофайлового приложения.
Примерный вывод:
Введите длину стороны куба: 3.48 Объем: 42.1442 Площадь поверхности: 72.6624
[Имя проекта: Lesson_2Lab1
, имена файлов HeaderL2Lab1.h
, ImpL2Lab1.cpp
, MainL2Lab1.cpp
]
✍ Алгоритм:
- Откройте Microsoft Visual Studio. Выберите в меню Файл/File -> Новый проект/New project. Выберите язык C++ и консольное приложение.
- Назовите проект Lesson_2Lab1.
- В окне Обозреватель решений/Solution Explorer найдите папку Файлы источники/Source files и в контекстном меню папки выбрать Добавить/Add -> Новый файл/New Item. Необходимо создать два
.cpp
файла и назвать их:ImpL2Lab1.cpp
– файл реализации иMainL2Lab1.cpp
– файл с функцией main. - Затем найдите папку Файлы заголовков/Header files и в контекстном меню папки выберите Добавить/Add -> Новый файл/New Item. Добавьте заголовочный файл с расширением
.h
и назовите егоHeaderL2Lab1.h
. - Сначала выполним задание без пользовательских функций. То есть, необходимо задать значение для стороны куба и посчитать объем и площадь поверхности куба.
- Объявите переменную типа
double
и назовите ееlength
. Запросите ввести значение для нее. Не забудьте подключить библиотекуiostream
для осуществления ввода и вывода в консоль: - Для того, чтобы окно консоли не закрылось сразу после вывода, необходимо добавить паузу (pause). Функция main должна возвратить 0:
- Объявите переменные для объема и площади. Выполните вычисление по формулам и присвойте результаты переменным:
- Выведите результаты в консоль:
- Запустите приложение и проверьте вывод. Покажите преподавателю
- Теперь будем создавать пользовательские функции для расчета объема и площади.
- Найдите строки кода с объявлением переменных и расчетами. Закомментируйте их:
- Создадим функцию с названием
getVolume
для вычисления объема. Функция должна возвращать значение типа double (вещественный тип), так как сторона куба тоже вещественного типа. Объявление (сигнатуру) функции необходимо расположить до функцииmain
: - Добавьте объявление переменной length в функцию
main
: - Создайте метод
getSurfaceArea
для вычисления площади поверхности куба. Метод также должен возвращать значение типаdouble
. Расположите код объявления перед функциейmain
: - Компилятор не извлечет функции, пока мы их не вызовем. Таким образом, необходимо вызвать функции и результат, который они вернут сохранить в переменные. Расположите код вызова в функцию
main
, присвоив возвращаемое значение соответствующим переменным: - После данных срок кода должен следовать вывод значений переменных (см. выше).
- Запустите приложение и проверьте вывод. Результаты должны быть такими же, как и при первом выполнении задания. Покажите результаты преподавателю.
- В окне Обозреватель решений/Solution Explorer выберите заголовочный файл (
HeaderL2Lab1.h
). В код файла добавьте объявление методов, предварительно вырезав их из главного файла (в главном файле их не должно остаться): - В окне Обозреватель решений / Solution Explorer выберите файл реализации (
ImpL2Lab1.cpp
). В данном файле необходимо разместить тело функций — их реализацию (вырежьте эти фрагменты кода из главного файлаMainL2Lab1.cpp
и добавьте сюда). И не забудьте подключить заголовочный файл в самой верхней строке: - Теперь можно удалить всё лишнее из главного файла
MainL2Lab1.cpp
. Итог должен быть следующим: - Запустите приложение и проверьте выходные данные. Результаты должны быть такими, какими они и были.
- В систему moodle необходимо загрузить три файла:
HeaderL2Lab1.h
,ImpL2Lab1.cpp
,MainL2Lab1.cpp
.
1) Без пользовательских функций и без многофайлового приложения:
#include <iostream> int main() { double length; std::cout << "Введите длину стороны куба: "; std::cin >> length; // … }
//… system("pause"); return 0; }
double volume = length * length * length; double surfaceArea = 6 * length * length;
std::cout << "Объем: " << volume << std::endl; std::cout << "Площадь поверхности: " << surfaceArea << std::endl;
2) Использование пользовательских функций:
//double volume = length * length * length;
//double surfaceArea = 6 * length * length;
double getVolume(double length); double getVolume(double length) { return length * length * length; } int main() { //…
int main() { double length;
double getSurfaceArea(double length); double getSurfaceArea(double length) { return 6 * length * length; }
double volume = getVolume(length); double surfaceArea = getSurfaceArea(length);
3) Создание многофайлового приложения
#pragma once // вычисление объема куба double getVolume(double length); // вычисление площади поверхности double getSurfaceArea(double length);
.h
мы не добавляем код реализации функции, а только ее объявление (сигнатуру функции). Для того, чтобы увидеть код работы функции (ее реализации) необходимо перейти в .cpp
файл.— Директива
pragma once
дает команду компилятору выполнять код только один раз. Даже если много файлов (пользователей) одновременно будут использовать данный класс, объявление методов должно быть единственным.— Перед каждой функцией необходимо размещать комментарии с пояснением того, для чего служит эта функция.
#include "HeaderL2Lab1.h" double getVolume(double length) { return length * length * length; } double getSurfaceArea(double length) { return 6 * length * length; }
— Символ решетки (
#
) означает директиву, в данном случае директиву подключения заголовочного файла.— В файле описана реализация двух функций, объявление которых представлено в заголовочном файле с расширением
.h
.
#include <iostream> #include " HeaderL2Lab1.h" int main(){ double length; std::cout << "please enter the cube side length: "; std::cin >> length; //double volume = length * length * length; //double surfaceArea = 6 * length * length; double volume = getVolume(length); double surfaceArea = getSurfaceArea(length); std::cout << "Volume: " << volume << std::endl; std::cout << "Surface area: " << surfaceArea << std::endl; system("pause"); return 0; }
Найти максимум из последовательности n вводимых целых чисел.
Примерный вывод:
Введите n >> 5 Введите 5 элементов 8 10 8 15 1 Maximum = 15
[Имя проекта: Lesson_2Lab1
, имена файлов FindMaxLab2.h
, mainLab2.cpp
, FindMaxLab2.cpp
]
✍Алгоритм:
- Создайте файл исходного кода main.cpp, заголовочный файл FindMaxLab2.h и файл для реализации функций FindMaxLab2.cpp.
- В коде mainLab2.cpp и FindMaxLab2.cpp подключите необходимые библиотеки и заголовочный файл:
- В файле main.cpp добавьте функцию для работы с кириллицей:
- Перейдите в файл mainLab2.cpp и в функции main() объявите переменные. Затем запросите там количество элементов массива:
- Перейдите в заголовочный файл и объявите функцию для поиска максимального числа с параметром — количество элементов массива:
- Реализацию функции будем осуществлять в файле FindMaxLab2.cpp. Добавьте код поиска максимального элемента из вводимых чисел:
- В файле mainLab2.cpp добавьте код вызова функции:
#include <iostream> #include <sstream> //тестирование операций с потоками #include "FindMaxLab2.h" #include <cstdlib> using namespace std; |
... int main() { setlocale(LC_ALL, "Russian"); ... |
... int n; cout<<"Введите n"<<endl; cin>>n; ... |
void FindMax (int n); |
... void FindMax (int n){ int max, x; cout<<"Введите "<<n<<" элементов"<<endl; cin>>max; for (int i=1;i<n; ++i) { cin>>x; if (x>max) max=x; } cout<<"Maximum = "<<max<<endl; } ... |
... FindMax(n); ... |
Создать проект. Реализацию всех требуемых функций размещать в дополнительном файле (.cpp), а в заголовочном файле — их описание. Реализовать задание в виде функции:
Даны два целых числа A и B (A < B). Вывести в порядке убывания все чётные числа, расположенные между A и B (включая числа A и B), а также количество N этих чисел.
Указания:
void
;-=
для счётчика цикла;Примерный вывод:
введите а и b, a < b 3 6 6, 4 количество четных = 2
[Имя проекта: Lesson_2Lab3
, имена файлов cycleLab3.h
, cycleLab3.cpp
, MainLab3.cpp
]
✍ Алгоритм:
- Создайте файл исходного кода main.cpp, заголовочный файл cycleLab3.h и файл для реализации функций cycleLab3.cpp.
- В коде mainLab3.cpp и cycleLab3.h подключите необходимые библиотеки и заголовочный файл:
- В файле mainLab3.cpp добавьте функцию для работы с кириллицей:
- Объявите и запросите две целочисленных переменных:
- Описание функции: перейдите в заголовочный файл и объявите функцию с двумя целочисленными параметрами, возвращающую пустое значение. Назовите ее notOdd:
- Установите курсор на описании и ждите, пока не появится символ лампочки слева. Щелкните по лампочке и выберите пункт "Создать определение в cycle.cpp".
- После чего перейдите в код реализации функции и добавьте код, предназначенный для обмена значений переменных a и b в случае, если a > b:
- Далее работаем с циклом. Поскольку в указании к заданию, сказано использовать операцию
-=
для счётчика цикла, то счетчик должен уменьшаться от большего значения (b) к меньшему (a): - Поскольку по условию задания функция ничего не возвращает (
void
), то вывод значения в консоль необходимо реализовать в самой функции: - Переключитесь на вкладку с файлом main.cpp и добавьте в код вызов функции:
- Запустите программу.
#include <iostream> #include <sstream> //тестирование операций с потоками #include "cycleLab3.h" #include <cstdlib> using namespace std; |
... int main() { setlocale(LC_ALL, "Russian"); ... |
... int a,b; cout << "введите а и b, a < b" << endl; cin >> a >> b; ... |
void notOdd(int a, int b); |
... void notOdd(int a, int b) { int k=0; a>b ? swap(a, b) : a=a ; ... |
Тернарная операция в C++:
"условие" ? "выражение 1" : "выражение 2";Если условие истинно, то выполняется выражение 1, иначе (условие ложно) выполняется выражение 2.
Функция
swap()
:
Функция предназначена для обмена значений своих аргументов.
... for (int i = b; i >= a; i -= 1) { if (i % 2 == 0) { cout << i << " "; k++; } } |
... cout << "количество четных =" << k << endl; |
... notOdd(a, b); |
mainLab3.cpp | cycleLab3.cpp | ||
|
|
- Создать проект с функцией для вычисления Евклидова расстояния между двумя точками на плоскости.
- Реализовать тестирующую программу.
AB = √(x2-x1)2 + (y2-y1)2
Подробно:
Создать функцию:
double distance ( double x1, double y1, double x2, double y2 ) |
которая вычисляет Евклидово расстояние между двумя точками на плоскости.
Параметры функции:
x1, y1, x2, y2 – вещественные координаты точек.
Возвращаемое значение:
расстояние между точками ( x1; y1 ), ( x2; y2 )
.
[Имя проекта: Lesson_2Lab4
, имена файлов func1Lab4.h
, ImpL2Lab4.cpp
, MainLab4.cpp
]
✍ Алгоритм:
- Создайте пустой проект (см. урок 1). Главный файл назовите mainLab4.cpp, заголовочный файл - func1Lab4.h
- В заголовочный файл добавьте необходимую директиву для работы с математическими функциями:
- Далее добавьте описание функции и ее реализацию:
- Перейдите на вкладку с главным файлом (mainLab4.cpp). подключите заголовочный файл и создайте функцию main():
- Инициализируйте 4 переменные вещественного типа для координат точек. Запросите их значения:
- Вызовите функцию и выведите в консоль результат:
- Необходимо проверить "неподходящие" координаты точек, т.е. проверка случаев:
- единичного отрезка,
- отрезка иррациональной длины,
- отрезка нулевой длины.
- Создайте заголовочный файл test.h (Обозреватель решений -> Заголовочные файлы -> Добавить -> Создать элемент -> Файл заголовка)
- Подключите заголовочный файл в код mainLab4.cpp, перед подключением добавьте директиву
#define NDEBUG
: - Добавьте в код заголовочного файла необходимую директиву для работы с функцией проверки (assert):
- Также добавьте в код заголовочного файла необходимую директиву для работы с математическими функциями и другие директивы:
- Создайте описание функции, возвращающей логическое значение. Функция без параметров:
- Поставьте курсор на код функции и дождитесь, чтобы слева появилось изображение лампочки. Щелкнув по нему, выберите "Копировать сигнатуру test_distance в буфер обмена".
- Спуститесь в коде на следующую строчку и вставьте фрагмент из буфера.
- Перед функцией добавьте в код константу для проверки точности сравнения вещественных чисел
- В код реализации функции проверки добавьте объявление и инициализацию переменных:
- Вставьте код проверки единичного отрезка:
- После выполнения проверки в конце функции необходимо возвратить истинное значение:
- Вся функция проверки:
- В файле исходного кода добавьте сначала вызов тестирующей функции, а затем основной функции:
#include <iostream> #include <cmath> using namespace std; |
... double distance(double x1, double y1, double x2, double y2); double distance(double x1, double y1, double x2, double y2) { return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); } |
#include <iostream> #include <cstdlib> // для system("pause"); #include "func1Lab4.h" using namespace std; int main() { system("pause"); return 0; } |
... int main() { double x1, y1, x2, y2; cout << "введите координаты точек: x1, y1, x2, y2" << endl; cin >> x1 >> y1 >> x2 >> y2; system("pause"); return 0; } |
Для подключения кириллицы в начале функции main() вызовите функцию:
... int main() { setlocale(LC_ALL, "Russian"); ... |
... cout << distance( x1, y1, x2, y2); |
Реализуйте тест:
... #define NDEBUG #include "test.h" ... |
...
#include <cassert>
... |
Функция
assert
анализирует аргумент, переданный ей. Если аргумент-выражение равен нулю (т.е. выражение ложно), сообщение записывается на стандартное устройство вывода ошибок и вызывается функцияabort
, работа программы прекращается.
... #include <iostream> #include <cmath> using namespace std; |
... bool test_distance(); |
... const double precision = 1E-16; ... |
... bool test_distance() { double x1 = 0, y1 = 0; double x2 = 1, y2 = 0; double result = 1; ... |
... assert ( abs ( distance (x1,y1,x2,y2) - result) < precision); ... |
... return true; } |
... bool test_distance() { double x1 = 0, y1 = 0; double x2 = 1, y2 = 0; double result = 1; // Тест 1 - единичный отрезок assert ( abs ( distance (x1,y1,x2,y2) - result) < precision); return true; } ... |
... int main() { test_distance(); double x1, y1, x2, y2; cout << "введите координаты точек: x1, y1, x2, y2" << endl; cin >> x1 >> y1 >> x2 >> y2; cout << distance( x1, y1, x2, y2); ... |
Рекомендации ко всем заданиям
Lesson_2Lab1 folder
).[Solution and Project name: Lesson_2Lab1
, files’ names tasks.h
, tasks.cpp
, main.cpp
]
* Данные пункты не обязательны к выполнению в том случае, если вы самостоятельно создадите три файла в едином проекте для выполнения всех заданий: главный файл, заголовочный файл и файл реализации.