Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Metodichka_lab1.doc
Скачиваний:
36
Добавлен:
13.11.2018
Размер:
6.74 Mб
Скачать

Использование параметров функции для обмена информацией между функциями.

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

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

Существует два способа передачи параметров в функцию: по значению и по адресу.

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

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

Рассмотрим пример программы, иллюстрирующий рассмотренные выше способы передачи параметров в функцию:

// Программа 4_4

// Способы передачи параметров в функцию

#include <iostream.h>

using namespace std;

void f(int i, int* j, int& k);

int main()

{

int i = 1, j = 2, k = 3;

cout << "i j k\n";

cout << i << " " << j << " " << k << endl;

f(i, &j, k);

cout << i << " " << j << " " << k;

return 0;

}

void f (int i, int* j, int& k)

{

i++; (*j)++; k++;

}

Результат работы программы:

i j k

1 2 3

1 3 4

Первый параметр (i) передается по значению. Его изменение в функции не влияет на исходное значение. Второй параметр (j) передается по адресу с помощью указателя, при этом для передачи в функцию адреса фактического параметра используется операция взятия адреса, а для получения его значения в функции требуется операция разыменования. Третий параметр (k) передается по адресу с помощью ссылки.

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

Если требуется запретить изменение параметра внутри функции, используется модификатор const, например: int f(const char*);

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

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

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

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

int myFunction (int, int);

int myFunction (long, long);

int myFunction (long);

Функция myFunction () перегружена с тремя разными списками параметров. Первая и вторая версии отличаются типами параметров, а третья — их количеством.

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

Перегрузка функций также называется полиморфизмом функций. Поли (гр. poly) означает много, морфе (гр. morphe) — форма, т.е. полиморфическая функция — это функция, отличающаяся многообразием форм.

Под полиморфизмом функции понимают существование в программе нескольких перегруженных версий функции, имеющих разные назначения. Изменяя количество или тип параметров, можно присвоить двум или нескольким функциям одно и то же имя. При этом никакой путаницы при вызове функций не будет, поскольку нужная функция определяется по совпадению используемых параметров. Это позволяет создать функцию, которая сможет, например, усреднять целочисленные значения, значения типа double или значения других типов без необходимости создавать отдельные имена для каждой функции — Averageints(), AverageDoubles() и т.д.

Предположим, требуется создать функцию, которая удваивает любое передаваемое ей значение. При этом хотелось бы иметь возможность передавать ей значения типа int, long, float или double. Без перегрузки функций пришлось бы создавать четыре разные функции:

int Doubleint(int);

long DoubleLong(long); . •

float DoubleFloat(float);

double DoubleDouble(double);

С помощью перегрузки функций можно использовать следующие объявления:

int Double(int);

long Double(long);

float DouDle(float);

double Double(double);

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

// Программа 4_5

// Пример полиморфизма функций

// Четыре одноименных функции удваивают значение аргумента каждого из четырех типов

#include <iostream.h>

using namespace std;

int Double (int); // Прототипы одноименных функций

long Double (long);

float Double (float);

double Double (double);

int main()

{

int myInt = 6500; // Исходные данные различных типов

long myLong = 6500;

float myFloat = 6.5F;

double myDouble = 6.5e20;

int doubledInt; // Объявление переменных для результата

long doubledLong;

float doubledFloat;

double doubledDouble;

cout << "ИСХОДНЫЕ ДАННЫЕ:\n";

cout << "myInt: " << myInt << "\n"; // Вывод исходных данных

cout << "myLong: " << myLong << "\n";

cout << "myFloat: " << myFloat << "\n";

cout << "myDouble: " << myDouble <<"\n\n";

cout << "ВЫЗЫВАЕМЫЕ ФУНКЦИИ:\n";

doubledInt = Double (myInt); // Вызовы одноименных функций

doubledLong = Double (myLong);

doubledFloat = Double (myFloat);

doubledDouble = Double (myDouble);

cout << "ВЫВОД РЕЗУЛЬТАТОВ:\n";

cout << "doubledInt: " << doubledInt << "\n"; // Вывод результатов

cout << "doubledLong: " << doubledLong << "\n";

cout << "doubledFloat: " << doubledFloat << "\n";

cout << "doubledDouble: " << doubledDouble << "\n";

return 0;

}

int Double (int original)

{

cout << "ФУНКЦИЯ Double(int)\n";

return 2 * original;

}

long Double (long original)

{

cout << "ФУНКЦИЯ Double(long)\n";

return 2 * original;

}

float Double (float original)

{

cout << "ФУНКЦИЯ Double(float)\n";

return 2 * original;

}

double Double (double original)

{

cout << "ФУНКЦИЯ Double(double)\n\n";

return 2 * original;

}

Результат работы программы:

Функция Double() перегружается для приема четырех типов: int, long, float и double. По виду вызова функции Double() ничем не отличаются друг от друга. Однако, компилятор определяет тип переданного аргумента, на основании которого выбирает соответствующий вариант функции. Результат работы этой программы подтверждает ожидаемую очередность вызова вариантов этой перегруженной функции.

Параметры функции, используемые по умолчанию.

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

long myFunction(int);

то она действительно должна принимать целочисленное значение. Если тип объявленного параметра не совпадет с типом передаваемого аргумента, компилятор сообщит об ошибке.

Из этого правила существует одно исключение, которое вступает в силу, если в прототипе функции для параметра объявляется стандартное значение. Это значение, которое используется в том случае, если при вызове функции для этого параметра не установлено никакого значения. Несколько изменим предыдущее объявление:

long myFunction(int x = 50);

Этот прототип нужно понимать следующим образом. Функция myFunction(int) возвращает значение типа long и принимает параметр типа int. Но если при вызове этой функции аргумент предоставлен не будет, используйте вместо него число 50. А поскольку в прототипах функций имена параметров не обязательны, то последний вариант объявления можно переписать по-другому:

long myFunction (int = 50);

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

long myFunction (int x)

Если при вызове этой функции аргумент не устанавливается, то компилятор присвоит переменной х значение 50. Имя параметра, для которого в прототипе устанавливается значение по умолчанию, может не совпадать с именем параметра, указываемого в заголовке функции: значение, заданное по умолчанию, присваивается по позиции, а не по имени.

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

Предположим, прототип функции имеет вид

long rnyFunction (int Paraml, int Param2, int Рагаm3);

тогда параметру Param2 можно назначить стандартное значение только в том случае, если назначено стандартное значение и параметру РагаmЗ. Параметру Paraml можно назначить стандартное значение только в том случае, если назначены стандартные значения как параметру Рагаm2, так и параметру РагаmЗ, Пример использование значений, задаваемых параметрам функций по умолчанию, показан в программе 4_6.

// Программа 4_6

// Использование стандартных значений параметров (по умолчанию)

#include <iostream.h>

using namespace std;

int VolumeCube(int length, int width = 25, int height = 1);

int main()

{

int length = 100;

int width = 50;

int height = 2;

int volume;

volume = VolumeCube ( length, width, height );

cout << "Первый объем равен: " << volume << "\n";

volume = VolumeCube ( length, width );

cout << "Второй объем равен: " << volume << "\n";

volume = VolumeCube ( length );

cout << "Третий объем равен: " << volume << "\n";

return 0;

}

VolumeCube (int length, int width, int height )

{

return (length * width * height);

}

Результат работы программы:

Первый объем равен: 10000

Второй объем равен: 5000

Третий объем равен: 2500

В прототипе функции VolumeCube() объявляется, что функция принимает три параметра, причем последние два имеют значения, устанавливаемые по умолчанию.

Эта функция вычисляет объем параллелепипеда на основании переданных размеров. Если значение ширины не передано, то ширина устанавливается равной 25, а высота — 1. Если значение ширины передано, а значение высоты нет, то по умолчанию устанавливается только значение высоты. Но нельзя передать в функцию значение высоты без передачи значения ширины.

В последующих строках инициализируются переменные, предназначенные для хранения размеров параллелепипеда по длине, ширине и высоте. Эти значения передаются функции VolumeCube(). После вычисления объема параллелепипеда результат выводится в соответствующей строке.

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

При третьем вызове функции VolumeCube() не передается ни значение ширины, ни значение высоты. Поэтому вместо них используются значения, заданные по умолчанию, и полученный результат также выводится на экран.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]