Параметры по умолчанию


В прототипе или при описании функции в её заголовке одному или нескольким формальным параметрам может быть назначено значение по умолчанию по тем же правилам, что при инициализации. При вызове таких функций фактические параметры, соответствующие умалчиваемым, могут быть опущены, и тогда функция будет выполняться с теми значениями, которые указаны в заголовке. Значение по умолчанию можно изменить, записав при вызове фактический вместо умалчиваемого параметра. Остальные фактические параметры должны быть обязательно заданы. Например, функцию с заголовком void fun62 (float f, char ch=’*’, int i=2); можно вызвать одним из следующих способов:

а) fun62 (2.5, ‘-‘, 11); // параметры получат значения: f=2.5, ch=’-‘, i=11;

б) fun62 (2.5, 196); // f=2.5, ch — символ с кодом 196, i=2 по умолчанию;

в) fun62 (196); // f=196 как вещественное, сh=’*’ и i=2 по умолчанию;

г) fun62(0.01, ‘*’, 33); // f=0.01, ch=’*’, i=33;

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

1) значение по умолчанию может быть задано либо в прототипе, либо при описании функции, но только в одном месте один раз;

2) в качестве умалчиваемых значений должны быть либо константы, либо глобальные переменные;

3) параметры со значениями по умолчанию должны быть последними в списке;

4) если при вызове функции опустили аргумент для параметра по умолчанию, то не надо писать аргумент и для всех оставшихся в списке. Например, если для функции fun62 надо изменить iна 196,то fun62 (0.11, 196); компилируется из-за совместимости целого и символьного типов, но неправильно выполняется, так как i останется по умолчанию (см. б)), а fun62(0.11 , , 196) не компилируется. Правильным будет следующий вызов: fun62(0.11 , ’*’ , 196);

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

int test=2;

void Out62(float f1, char str2[]="hello", char c3='*', int p4=test )

{ textcolor(12);

cprintf("%f %s %c %d\n\r", f1, str2, c3, p4);

}

int main(int argc, char* argv[])

{ Out62(11,"MMF",65);

Out62(11);

int q1=1111; Out62(q1,";",196 ,9);

// Целое число можно передать вместо вещественного f1

getch(); return 0;

}

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

Упражнение. Определить результат выполнения последней программы.

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

В “старом” языке С все имена функций должны быть уникальны в одном проекте. Это плохо и неудобно при работе с функциями, которые выполняют одинаковые или похожие действия с разными типами данных. Классический пример этого — стандартные функции abs(), labs(), fabs(), которые возвращают абсолютное значение, соответственно, целого, длинного целого (longint) и числа с плавающей точкой. В С++ можно определить несколько функций с одним и тем же именем, которые отличаются типами параметров и реже их количеством. Тогда говорят, что функции перегружены.

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

void RR ( int &, int &);

void RR ( float &, float &);

void RR ( char &, char &);

int main()

{ int i1=11, i2=22; RR(i1,i2);

cout<<"\ni1="<<i1<<" i2="<<i2<<endl;

float f1=3.4, f2=5.6; RR(f1,f2);

cout<<"\nf1="<<f1<<" f2="<<f2<<endl;

char c1='a', c2='b'; RR(c1,c2);

cout<<"\nc1="<<c1<<" c2="<<c2<<endl;

getch(); return 0;

}

void RR(int &u, int &v) {int t; t=u; u=v; v=t; }

void RR(float &u, float &v) {float t; t=u; u=v; v=t; }

void RR(char &c1, char &c2) { char c; c=c1; c1=c2; c2=c; }

Какой вариант функции RR из трёх вызывается в main()? Компилятор автоматически выберет необходимую версию функции на основании типа используемых в функции фактических параметров. Первый раз вызывается первый вариант функции для целых параметров, второй раз — для вещественных значений и, наконец, для символьных.

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

Нельзя, чтобы перегружаемые функции отличались только типом возвращаемых значений. Например, такая перегрузка функций int FUN2(int ); float FUN2 (int); компилятору не понравится !

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

Г л а в а 3
ВВЕДЕНИЕ В ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ

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

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

Примеры

П р и м е р 1. Разработаем простейший класс для работы с двумя целыми числами. В класс включим конструктор и следующие функции: вывод двух целых чисел; вычисление их суммы; проверка, делится ли одно число на другое без остатка; изменение двух целых чисел по правилу: наименьшее число или оба, если они одинаковы, умножаем на величину par, которая передаётся как параметр функции при её вызове.

class FirstCl // Описание класса с именем FirstCl

{ int a,b; // поля класса, т. е. переменные

public: // атрибут доступа(см.§ 2)

/* Заголовок конструктора. Это функция, которая имеет то же имя, что и класс; тип возвращаемого значения не записывается.*/

FirstCl(int x, int y);

/* Заголовки четырёх функций (методов) класса, оформленных как внешние. Они похожи на прототипы обычных самостоятельных функций, только поля класса, т. е. два целых числа, в качестве параметров не записываем */

void MyPrint();

int MySum();

bool MyTest();

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

void Change (int );

}; // конец описания класса

/* Текст внешнего конструктора. Перед именем внешнего конструктора и каждой внешней функции записываем имя класса и операцию “::” (разрешение области видимости). */

FirstCl::FirstCl (int x, int y)

{ a=x; b=y;

};

// Тексты четырёх внешних методов.

void FirstCl::MyPrint()

{ cout<<"\nThe first number "<<a<< " The second number "<<b <<endl;

} ;

int FirstCl::MySum()

{ return a+b;

};

/* Логическая функция, возвращающая true или false в зависимости от того, делится ли a на b без остатка (для 10 и 3 — false, 3 и 10 — false, 10 и 2 — true, 2 и 10 — false). */

bool FirstCl::MyTest()

{return !(a%b)? true : false;

};

void FirstCl::Change (int par)

{ if (a>b) b*=par;

else if (a<b) a*=par;

else { b*=par; a*=par;

}

};

/* В головной функции создаём объект, т. е. переменную типа класс, и вызываем включённые в класс методы. */

int main(int argc, char* argv[])

{ FirstCl obj(10,2);

/* Объявили объект obj и одновременно с этим вызвали конструктор, с помощью которого создаётся объект, и в класс передаются числа 10 и 2. Методы (функции) этого объекта будут выполняться для этих чисел. Повторно при вызове методов класса эти числа не передаём. Как и для самостоятельных функций, при объявлении объекта можно в качестве “фактических параметров” для конструктора передать не только константы, а и значения предварительно объявленных и определённых, например, введённых, переменных:

int A,B; cin>>A>>B;

FirstCl obj(A,B ); */

/* При вызове функций записываем имя объекта (obj), но не класса, и после точки имя функции (MyPrint). */

obj.MyPrint();

cout<<"\nSum "<<obj.MySum();

if (obj.MyTest()) cout<<"\n-----";

else cout<<"\n+++++";

obj.Change(10); cout<<"\nChanging ";

obj.MyPrint();

getch(); return 0;

}

При вызове функций класса есть аналогия с обычными самостоятельными функциями, не членами класса. Функции типа void вызываются отдельно (obj.MyPrint(); obj.Change(10);). Вызов функции с возвращаемым с помощью return единственным результатом записывается непосредственно в выражении, а значит, в операторе, в котором используется значение функции

(if (obj.MyTest() ) …).

Ещё раз обратим внимание на следующие особенности вызова методов класса:

· перед именем метода записывается имя объекта (а не класса!) и после точки имя метода. При необходимости в скобках записываем фактические параметры (см. функцию Change);

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

П р и м е р 2. Разработать класс для работы с одномерным массивом наибольшей размерности 20. В отличие от первого примера, все функции оформим как встроенные. Их назначение приведено в комментариях:

#define MaxSize 20

/*Определили макрос, используемый в качестве наибольшей размерности массива */

class ClArray

{ int n;

float A[MaxSize];

public:

/* Конструктор инициализирует только одно поле — размерность массива. При этом осуществляется проверка передаваемого значения. Массив, который является вторым полем класса, определяется с помощью функции MyInp */

ClArray (int m)

{ n=m; if (n>MaxSize || n<1) n=10;

} ;

// Функция (метод) для ввода массива.

void MyInp()

{ int x=1, y; y=wherey();

for(int i=0; i<n; i++, x+=7)

{ gotoxy(x,y); cin>>A[i];

}

} ;

/* Функция (метод) для “цветного” вывода массива. При этом числа num выводятся цветом С1, а остальные — цветом С2 */

void MyOut(int C1, int C2, float num)

{ cout<<endl;

for ( int i=0; i<n; i++)

{ if (A[i]==num) textcolor ( C1 );

else textcolor ( C2 );

cprintf ( "%10.4f", A[i] );

}

}

/* Логическая (булевская) функция (метод), возвращающая true или false в зависимости от того, найдено число t в массиве или нет */

bool Test (float t)

{ for (int i=0; i<n; i++)

if (A[i]==t) return true;

return false;

}

/* Функция (метод), которая в массиве каждое наибольшее число меняет на наименьшее и наоборот. Кроме того, функция возвращает наибольшее и наименьшее значения. */

void MyChange ( float &mx, float &mn)

{ mx=mn=A[0];

for(int i=0; i<n; i++)

{ mx= A[i]>mx? A[i] : mx;

mn= A[i]<mn? A[i] : mn; }

for(int i=0; i<n; i++)

if (A[i]==mx) A[i]=mn;

else if (A[i]==mn) A[i]=mx;

} // end of the last function

} ; // end of class

/* В головной функции в цикле создаём объекты, то есть работаем с несколькими одномерными массивами, пока не введём в качестве размерности число 0. */

int main()

{ int N=5; float num;

do { ClArray ObArr(N);

ObArr.MyInp(); // ввод массива

while(1) // цикл для поиска нескольких чисел в массиве

{ cout<<"\n Number for find (1000 -- exit)"; cin>>num;

if (num==1000) break;

ObArr.MyOut ( 2, 5, num); // вывод массива разным цветом

if ( ObArr.Test ( num ) )

cout <<" \n Find the number " ;

else cout<<"\n Do not find the number ";

cout<<num;

}

float MyMx, MyMn;

/* Изменяем массив и возвращаем в функцию main наибольшее (MyMx) и наименьшее (MyMn) значения. */

ObArr.MyChange(MyMx, MyMn);

/* Вывод массива с выделением другим цветом наибольшего значения (MyMx). */

ObArr.MyOut(2,5,MyMx);

/* Вывод массива с выделением другим цветом наименьшего значения (MyMn). */

ObArr.MyOut(2,5,MyMn);

cout<< "\n Size of array (0 -- exit)"; cin>>N;

} while ( N);

return 0;

}



Дата добавления: 2016-07-18; просмотров: 2041;


Поиск по сайту:

Воспользовавшись поиском можно найти нужную информацию на сайте.

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.028 сек.