Партнерка на США и Канаду по недвижимости, выплаты в крипто

  • 30% recurring commission
  • Выплаты в USDT
  • Вывод каждую неделю
  • Комиссия до 5 лет за каждого referral

Лекция 6

1. Перегрузка функций

Язык С++ позволяет создавать несколько  различных функций с одинаковыми именами. Это называется перегрузкой функций. Такие функции должны отличаться друг от друга списками параметров (типом или количеством).

Например:

int func(int x, int y);

int func(long x, long y);

int func(double x);

Например:

В результате перегрузки функций происходит явление, называемое полиморфизмом. При этом никакой путаницы происходить не будет, поскольку нужная функция будет определяться по совпадению используемых параметров. Это позволит, например, создать функцию, которая сможет усреднять целочисленные значения для любых типов данных, не создавая отдельные функции для каждого типа.

Например, можно создать функции

int Average(int, int);

long Average(long, long);

float Average(float, float);

double Average(double, double);

В вызывающей функции достаточно указать имя функции и передать параметры нужного типа. Компилятор сам определит, какую из четырех описанных функций нужно будет вызвать. в зависимости от типа фактических параметров.

2. Модули

Иногда программный код оказывается слишком большим и сложным, чтобы хранить его в одном файле. В таком коде сложно ориентироваться и при возникновении ошибок их будет трудно искать и исправлять. К тому же, после исправления отдельных ошибок будет необходимо перекомпилировать заново всю программу, что при больших объемах может занять достаточно много времени.

В таких случаях удобнее разбить программу на несколько исходных файлов, которые обычно называют модулями. Каждый из этих модулей можно компилировать отдельно, а затем объединить их в процессе построения конечной программы.

НЕ нашли? Не то? Что вы ищете?

Процесс объединения отдельно скомпилированных модулей называется связыванием (компоновкой).

Чтобы создать отдельные модули программы, необходимо в окне Solution Explorer с помощью контекстного меню для пункта Source File создать отдельные файлы проекта.  Все они будут иметь расширение. cpp и будут компилироваться отдельно (пункт меню Build, Compile или Ctrl-F7). Основная программа при этом может содержать только главную функцию main и прототипы всех остальных функций, которые содержатся в других модулях. После успешной компиляции  каждого отдельного модуля необходимо выполнить компоновку проекта с помощью пункта Build, Build Solution или клавиши F7. Далее можно запускать программу на выполнение обычным способом.

Кроме этого, в одном модуле можно использовать функции других модулей. Для этого в каждом модуле необходимо описать описывать их прототипы. Удобнее создать заголовочный файл (пункт «Заголовочные файлы в «Обозревателе решений»), в котором будут описаны все прототипы функций, а затем включить его с помощью директивы #include. Заголовочные файлы обычно имеют расширение. h.

Рассмотрим создание модулей на примере.

Пример. Разработать программу, которая определяет тип треугольника по его сторонам (равносторонний, равнобедренный, прямоугольный, обычный или не существует), а также вычисляет его площадь и периметр. Программа должна запрашивать стороны треугольника и выдавать на экран меню в следующем виде:

Выберите номер пункта:

1.Периметр

2.Площадь

3.Тип

4.Выход

Заголовочный файл:

treug. h

void tip(float a, float b, float c);

float perimetr(float a, float b, float c);

float square(float a, float b, float c);

Реализация:

Основной модуль – index. cpp

#include <iostream>

#include <iomanip>

#include “treug. h”

using namespace std;

void main()

{

       float x, y,z;

       setlocale (LC_ALL,"rus");

       cout<<"Введите стороны треугольника"<<endl;

       cin>>x>>y>>z;

       int punkt=0;

       while (punkt!=4)

       {

               cout<<"Выберите номер пункта:"<<endl;

               cout<<"1.Периметр"<<endl;

               cout<<"2.Площадь"<<endl;

               cout<<"3.Тип"<<endl;

               cout<<"4.Выход"<<endl;

               cin>>punkt;

               switch (punkt)

               {

               case 1: cout<<"Периметр="<<setprecision(2)<<fixed<<perimetr(x, y,z)<<endl; break;

                       case 2: cout<<"Площадь="<<setprecision(2)<<fixed<<square(x, y,z)<<endl; break;

                       case 3: tip(x, y,z); break;

                       case 4: break;

                       default: cout<<"Неверный ввод"<<endl; break;

               }

       }

}

Дополнительный модуль – module. cpp

#include <iostream>

#include <iomanip>

#include <cmath>

using namespace std;

void tip(float a, float b, float c)

{

       int t;

       t=0;

       if ((a==b)&&(a==c)&&(c==b))

       {

               cout<<"Равносторонний"<<endl; t=1;

       }

       if ((a==b)&&(a==c)&&(c!=b)||(a==b)&&(a!=c)&&(c==b)||(a!=b)&&(a==c)&&(c==b))

       {

               cout<<"Равнобедренный"<<endl; t=1;

       }

       if ((a*a+b*b==c*c)||(a*a+c*c==b*b)||(c*c+b*b==a*a))

       {

               cout<<"Прямоугольный"<<endl; t=1;

       }

       if ((a+b<=c)||(a+c<=b)||(b+c<=a))

       {

               cout<<"Не существует"<<endl; t=1;

       }

       if (t==0)

       {

                       cout<<"Обычный"<<endl; 

       }

}

float square(float a, float b, float c)

{

       float p;

  p=(a+b+c)/2;

       return (sqrt(p*(p-a)*(p-b)*(p-c)));

}

float perimetr(float a, float b, float c)

{

       return (a+b+c);

}

3. Указатели

Указатели широко используются в C++. Именно их наличие сделало этот язык более удобным для системного программирования. Идея работы с указателями состоит в том, что пользователь работает с адресом ячейки памяти и имеет возможность динамически создавать и уничтожать переменные.

Как правило, при обработке оператора объявления переменной

тип имя_переменной;

компилятор автоматически выделяет память под переменную в соответствии с указанным типом:

Доступ к объявленной переменной осуществляется по ее имени. При этом все обращения к переменной меняются на адрес ячейки памяти, в которой хранится ее значение. При завершении программы или функции, в которой была описана переменная, память автоматически освобождается.

Доступ к значению переменной можно получить иным способом — определить собственные переменные для хранения адресов ячеек памяти. Такие переменные называют указателями. С помощью указателей можно обрабатывать массивы, строки и структуры, динамически создавать новые переменные в процессе выполнения программы (а не на этапе компиляции), передавать адреса фактических параметров.

Указатель — это переменная, значением которой является адрес памяти, по которому хранится объект определенного типа (другая переменная). Например, если C - это переменная типа char, а P - указатель на C, то, значит, в P находится адрес, по которому в памяти компьютера хранится значение переменной C.

Как и любая переменная, указатель должен быть объявлен. При объявлении указателей всегда указывается тип объекта, который будет храниться по данному адресу:

Например:

int *p

Звездочка в описании указателя относится непосредственно к имени, поэтому, чтобы объявить несколько указателей, ее ставят перед именем каждого из них:

float *x, y, *z;

Операция получения адреса обозначается знаком &. Она возвращает адрес своего операнда. Например:

float a; //объявлена вещественная переменная a

float *adr_a; //объявлен указатель на тип float

adr_a = &a; //оператор записывает в переменную adr_a

//адрес переменной a

Операция разадресации *  возвращает значение переменной, хранящееся в по заданному адресу, то есть выполняет действие, обратное операции &:

float a, b; //объявленs вещественная переменная a и b

float *adr_a; //объявлен указатель на тип float

adr_a=&a;

b = *adr_a; //оператор записывает в переменную b

//вещественное значение, хранящееся по адресу adr_a

Значение одного указателя можно присвоить другому. Если указатели одного типа, то для этого применяют обычную операцию присваивания. Рассмотрим ее на примере:

#include <iostream>

using namespace std;

int main()

{

float PI=3.14159, *p1, *p2;

p1=p2=&PI;

cout<<"По адресу p1="<<p1<<" хранится *p1="<<*p1<<"\n";

cout<<"По адресу p2="<<p2<<" хранится *p2="<<*p2<<"\n";

system ("pause");

return 0;

}

Если указатели ссылаются на различные типы, то при присваивании значения одного указателя другому, необходимо использовать преобразование типов.

Пример

#include <iostream>

using namespace std;

int main()

{

float PI=3.14159; //объявлена вещественная переменная PI

float *p1; //объявлен указатель на float - p1

double *p2; //объявлен указатель на double - p2

p1=&PI; //переменной p1 присваивается значние адреса PI

p2=(double *)p1; //указателю на double присваивается значение,

//которое ссылается на тип float

cout<<"По адресу p1="<<p1<<" хранится *p1="<<*p1<<"\n";

cout<<"По адресу p2="<<p2<<" хранится *p2="<<*p2<<"\n";

system ("pause");

return 0;

}

В указателях p1 и p2 хранится один и тот же адрес, но значения, на которые они ссылаются, оказываются разными. Это связано с тем, что указатель типа *float адресует 4 байта, а указатель *double - 8 байт. После присваивания p2=(double *)p1; при обращении к *p2 происходит следующее: к переменной, хранящийся по адресу p1, дописывается еще 4 следующих байт из памяти. В результате значение *p2 не совпадает со значением *p1.

Указатели можно использовать также для передачи параметров в функцию. Этот способ аналогичен способу передачи параметров по ссылке.

Для передачи данных по адресу требуется после типа переменной указать символ «*» (операция разадресации).  Чтобы передать в функцию фактический параметр по адресу, нужно использовать операцию взятия адреса «&».

Если требуется запретить изменение параметра внутри функции, используют модификатор const (при попытке изменения значения будет выдаваться ошибка компилятора). Заголовок функции в общем виде будет выглядеть так:

тип имя_функции (const тип_переменной имя_переменной, …)

Пример

#include <iostream>

//Определяем прототипы функций

int sum_value(int); //Функция будет принимать обычный параметр

int sum_ref(int &); //Функция будет принимать ссылку

int sum_ptr(int *); //Функция будет принимать указатель

//Определяем функции. 3 функции по прототипам + main

int sum_value(int x) //В переменную x присваивается значение извне. x - обычный параметр

{

x=x+1; //x увеличивается на один

return x; //возвращаем полученный x

}

int sum_ref(int &x) //В функцию передается ссылка, она ссылается на объект извне

{

x=x+1; //Увеличили x на один

return x; //возвращаем полученный x

}

int sum_ptr(int *x) //В функцию передается указатель. Указатель это адрес переменной извне

{

*x=*x+1; //Для того, чтоб работать с указателем как с переменной, нужно его разыменовать

return *x; //Если не прописать звездочки, будет выведен адрес, а не значение объекта

}

//Внутри функции main функции вызываются по очереди

void main()

{

int value=10; //Переменная value будет выступит передаваемым параметром в функцию

cout<<sum_value(value); //Первое обращение. Передача в функцию обычного параметра

cout<<value;

cout<<sum_ref(value); //Второе обращение. Передача в функцию параметра ссылки

cout<<value;

cout<<sum_ptr(&value); //Третье обращение. Передача в функцию параметра указателя

cout<<value;

}