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

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

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

Пример

#include<cmath>

#include<iostream>

using namespace std;

double root(double x, unsigned int n=2)

{

if(n==2) return sqrt(x);

return exp(log(x)/n);

}

int main()

{

cout<<root(4) <<endl; /*То же, что и root(4,2)*/

cout<<root(64, 3)<<endl;

return 0;

}

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

Однако здесь следует обратить внимание на другое: второй параметр функции по умолчанию имеет значение 2. Это видно из описания функции: после имени параметра присутствует знак «=» и значение по умолчанию. Поэтому данной функции при вызове можно передавать либо один, либо два параметра, что демонстрируется в функции main. Не будет ошибкой вызов функции в виде root(4,2), и это в определенной степени способствует прозрачности кода. С другой стороны, если функция имеет десяток параметров, из которых половина практически всегда имеет одни и те же значения, то можно существенно уменьшить код, придав им значения по умолчанию.

Отметим некоторые ситуации, в которых имеет смысл использовать такой подход (и это реализовано в системных функциях):

· Чтение символьной строки с консоли. Естественным ограничителем является символ перевода строки, поэтому по умолчанию соответствующий параметр имеет значение ‘\n’. При желании можно указать другой символ-ограничитель.

· Вывод табулированного текста (в несколько колонок равной ширины). Колонки принято разделять пробелами, однако можно использовать и другой символ-разделитель.

При использовании параметров функции со значениями по умолчанию нужно придерживаться следующих правил:

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

2. Следует крайне аккуратно разрабатывать перегруженные функции с параметрами, имеющими значения по умолчанию. Например, компилятор допускает перегрузку функции следующим образом:
int f(int x, int y=1)
{
return x*y;
}
int f(int a){
return 2*a;
}
Но попытка вызвать такую функцию оператором f(3) приводит к ошибке компиляции, так как невозможно определить, что имел в виду программист под этим вызовом.

3. Параметры со значениями по умолчанию должны быть простых типов: числовые, булевы, указатели (в частности, строки как указатели на массивы символов). Массивы и структуры не могут иметь значения по умолчанию.

Пример вычисления площади фигуры (под графиком функции)

Найти площадь фигуры, ограниченной линиями x=a,

x=b, y=0, y=f(x). Площадь ф. считаем равной сумме площадей

N трапеций. Высота трапеции – H=(b-a)/N.

S=H*(f(a) + f(a+H) + f(a+H) + f(a+2H) + … + f(b))/2

#include<iostream>

using namespace std;

double f(double);

double MyS(double,double,unsigned =1000000);

int main()

{

double a,b;

unsigned N;

a=0.;

b=3.;

cout<<MyS(a,b[,10])/9*4<<endl;

return 0;

}

double f(double x)

{

return sqrt(9-x*x);

}

double MyS(double c, double d, unsigned N)

{

double H=(d-c)/N;

double S=(f(c)+f(d))/2.;

for(c+=H; c<d; c+=H)

S+=f(c);

return S*H;

}

Стражи включения файлов-заголовков (include guard)

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

#pragma once - специфичная для MSVS команда


Лучше файлы заголовков, например файл с именем myfile.h, оформлять в следующем стиле:

#ifndef MYFILE_H

#define MYFILE_H

содержимое h-файла

#endif

А еще надежнее использовать их вместе, если поддерживает компилятор.

Ссылка на аргументы

Ссылка является псевдонимом, или альтернативным именем переменной.

Важным применением ссылок является передача аргументов в функции. Если передача переменной-аргумента в функцию осуществляется по значению, то … Передача по ссылке происходит по другому механизму. Передается ссылка на эту переменную (адрес переменной-аргумента в памяти), и функция имеет прямой доступ к значениям аргументов.

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

int main()

{

void order(int&, int&);

int n1=99, n2=11;

int n3=22, n4=88;

order(n1, n2);

order(n3, n4);

cout<<”n1 =”<< n1 <<endl;

cout<<”n2 =”<< n2 <<endl;

cout<<”n3 =”<< n3 <<endl;

cout<<”n4 =”<< n4 <<endl;

return 0;

}

void order(int& numb1, int& numb2)

{

if (numb1 > numb2)

{

int temp = numb1;

numb1 = numb2;

numb2 = temp;

}

}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: