Новичкам тяжело понимать функции. С одной функцией мы уже работали: функция main(), внутри которой пишем наши программы:
C++
1
2
3
intmain(){
//Наш блок кода
}
Функции в языке С++ представляют собой мини-программы.
C++
1
2
3
4
5
6
7
voidfoo(){//Функция foo
}
intmain(){//Функция main
}
Это мини-программы, к которым программист может обращаться много раз в любое удобное время:
C++
1
2
3
4
5
6
7
8
9
10
11
12
voidfoo(){
}
intmain(){
foo();//Обращение к функции foo
//что-то можно сделать
foo();//Обращение к функции foo
//что-то можно сделать
foo();//Обращение к функции foo
//что-то можно сделать
}
Вы можете, например, замерить время работы вашего кода несколько раз. Это к вопросу о том, что можно сделать. Можно делать что-то другое. Суть в том, что зная имя функции и описание внутри круглых скобок функции, вы можете обращаться к функции в любом удобном месте кода. Вот пример трёх вызовов функции foo, благодаря которым три раза будет выведен текст на экран:
C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream.h>
voidfoo(){
cout<<"function foo()"<<'\n';
}
intmain(){
foo();//Обращение к функции foo
foo();//Обращение к функции foo
foo();//Обращение к функции foo
cin.get();
}
Вы можете создавать много собственных функций и вызывать каждую из них, когда она будет нужна:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//Borland C++ 3.1 Функции Листинг #2
#include <iostream.h>
/*==============НАШИ СОБСТВЕННЫЕ ФУНКЦИИ=====================*/
voidfoo3(){
cout<<"function foo3()"<<'\n';
}
voidfoo2(){
cout<<"function foo2()"<<'\n';
}
voidfoo1(){
cout<<"function foo1()"<<'\n';
}
/*============КОНЕЦ НАШИХ СОБСТВЕННЫХ ФУНКЦИЙ===============*/
intmain(){
foo3();//Обращение к функции foo3
foo2();//Обращение к функции foo2
foo1();//Обращение к функции foo1
cout<<'\n';//я вам для наглядности разделяю вывод на экран переносом строки
//в любом порядке
foo3();//Обращение к функции foo3
foo2();//Обращение к функции foo2
foo1();//Обращение к функции foo1
cin.get();
}
Может вам непонятно, зачем это нужно? Элементарный пример: создание меню в консоли.
Функции помогают рассредоточить большую кашу на внутренние для программы задачи. Вы выделяете некоторую подзадачу и выносите её в отдельную функцию.
Функции нужно писать снизу-вверх. Хотя в С++ порядок функций может не иметь значения, но если вы совсем новичок, то некоторое время можете придерживаться правила написания функций снизу-наверх. Так, у меня в коде, если смотреть на названия функций снизу-наверх, то видно, что на самом деле они идут по порядку: main, foo1(), foo2(), foo3()
Функции состоят из 4 частей: тип, название функции, круглые скобки и фигурные скобки.
ТИП
Название
Список параметров
Блок кода
int
main
()
{}
void
foo
()
{}
Все функции в языке С++ обязательно имеют тип, название, список параметров и блок кода. Список параметров может быть или пустым, или заполненный параметрами. Когда список параметров пуст — используются пустые круглые круглые скобки. В блоке кода пишется основной код, который должен выполниться при срабатывании функции.
Первоначальная задача функций порождать значение или полноценный объект, произведя вычисление
Новички часто не понимают, что обозначает возвращение из функции какого-то значения, зачем функция что-то возвращает, и вообще плюются на страшный для них и непонятный return
Прежде всего функции нужны для вычислений, чтобы производить какие-то вычисления, нужно что-нибудь для вычисления, нужны входные данные. Внутри функции программист описывает какое-либо вычисление, а результат работы этого вычисления возвращает из функции. Возвращение из функции результата нужно для того, чтобы вычисленный результат можно было задействовать в каком-то нужном месте внутри основной программы. Функции возвращают или значение, или объект. Возвращаемое значение или объект можно сохранять в подходящую по типу переменную, а какой тип окажется подходящим — определяется типом, приписываемом к функции.
Если тип, приписанный к функции не void, то внутри блока кода функции обязательно должно быть return
Чтобы задать входные данные для вычисления, используют список параметров. В списке параметров указывают, какие данные должна будет переваривать функция. Список параметров — это набор объявлений, описывающих какие входные данные должна ждать функция.
Простейший вариант работы с функцией — это написание функции сложения двух чисел, возвращающей результат сложения:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//clang Функции Знакомство Листинг #4/1
#include <iostream>
usingnamespacestd;
/*ФУНКЦИЯ СУММЫ ДВУХ ЧИСЕЛ*/
intsum(inta,intb){
intc;
c=a+b;//основное вычисление
returnc;//результат вычисления уходит во внешний мир
Я обозначил для вас внутри кода одинаковые участки. Функцию можно сравнить с некоторого рода вычисляемой переменной: вы отдаёте в функцию несколько значений, они внутри функции используются в вычислении, а вычисление, произведённое функцией, отдаётся из функции подобно значениям переменных. Только функция не является переменной, это нужно учитывать. Для хорошего восприятия первое время можете считать, что функция является такой переменной, которая требует в себя закладки данных с целью использования заложенных данных в вычислении. В случае суммы в качестве данных мы использовали слагаемые. На самом деле этот же код суммы можно писать короче:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//Borland C++ 3.1 Функции Листинг #4/2
#include <iostream>
usingnamespacestd;
/*ФУНКЦИЯ СУММЫ ДВУХ ЧИСЕЛ*/
intsum(inta,intb){
returna+b;//результат вычисления уходит во внешний мир
Внутри круглых скобок, в списке параметров, заявляются типы, которые будут использоваться в вычислении и даются названия, чтобы входящие данные не оказались неизвестно-безымянными. Описание списка параметров напоминает объявление обычных переменных, отличий почти нет. Но вы можете оставить только названия типов, а названия переменных не написать, тогда функция сможет съесть столько данных, сколько описано в списке параметров, но вы не сможете с ними работать, потому что связи у вас с пришедшими данными никакой не будет.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
usingnamespacestd;
intfoo(int,int){
//Вы ничего не можете сделать с пришедшими данными
//потому что у вас нет с ними связи
cout<<"foo()"<<endl;//чтобы было видно, что функция работает
return0;
}
intmain(){
inta,b;
foo(a,b);
}
Обычно, сколько вы указываете в списке параметров данных, столько данных надо кормить функции при использовании функции. Например, в нашей функции суммы мы заявляли в описании функции два входящих в параметры значения, при этом каждое значение заявлялось как int, поэтому при вызове функции мы кормили функцию двумя аргументами-переменными.
Список параметров — это набор данных, заявленных для функции. Описываются один раз.
Аргументы — это набор данных, отдаваемых функции во время обращения к функции, используются сколько угодно раз.
В списках параметров разных функций можно задавать одинаковые названия входящим данным:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Функции Листинг #5
voidfoo(inta,intb){//Внутри круглых скобок пишутся парамеры, через запятую
//т. е. сообщаем функции, чем будем её кормить
//Имена a и b видимы только в пределах фигурных скобок
}
voidsum(inta,intb){//Внутри круглых скобок пишутся парамеры, через запятую
//т. е. сообщаем функции, чем будем её кормить
//Имена a и b видимы только в пределах фигурных скобок
}
intmain(){
}
Каждый уходящий в функцию аргумент внутри функции нызывается именем, заявленным в списке параметров функций. Порядок именования происходит слева-направо. Функция при обнаружении жданного гостя как будто бы заявляет: "Мне не важно кем ты был там, здесь ты будешь…".
Понимайте, где аргументы и где параметры:
C++
1
2
3
4
5
6
7
8
9
10
//Псевдокод
voidfoo(список_параметров){
}
intmain(){
foo(список_аргументов);
foo(список_аргументов);
foo(список_аргументов);
}
Уходящие вовнутрь функции аргументы внутри функции называются таким образом, как заявлял программист:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
//Функции Знакомство Листинг #6
voidfoo(inta,intb){
//Первый параметр имеет имя "a", поэтому первое входящее значение получает имя "a"
//Второй параметр имеет имя "b", поэтому второе входящее значение получает имя "b"
}
intmain(){
intvalue1=100;//Два значения
intvalue2=500;//будут скормлены функции
foo(value1,value2);//Точка вызова функции и передача в функцию значений
foo(value2,value1);//Точка вызова функции и передача в функцию значений
}
При первом обращении к функции значение из аргумента value1 окажется в параметре a, значение из аргумента value2 окажется в параметре b.
При втором обращении к функции значение из аргумента value2 окажется в параметре a, азначение из аргумента value1 окажется в параметре b.
Как будто бы по полочкам раскладывается.
Когда вы обращаетесь к функции, то вы кормите функцию аргументами. Если существует функция, способная переварить отдаваемые аргументы, то такая функция сработает, если подходящей функции нет, то будет ошибка:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Функции Знакомство Листинг #7
voidfoo(inta,intb){
//Первый параметр имеет имя "a", поэтому первое входящее значение получает имя "a"
//Второй параметр имеет имя "b", поэтому второе входящее значение получает имя "b"
}
intmain(){
intvalue1=100;//Два значения
intvalue2=500;//будут скормлены функции
foo(value1,value2);//Точка вызова функции и передача в функцию значений
foo(value2,value1);//Точка вызова функции и передача в функцию значений
foo(value1);//Попытка вызова несуществующей функции
}
Код, показываемый в листинге #7, компилятор собрать не сможет. В последней попытке вызова функции программист кормит функцию одним аргументом, но функции с одним параметром в коде нет. Нет того, что должно быть вызвано. Компилятор не находит функции и ругается на вас матом.
За исключением функций, в списке параметров которых явно указано, что количество аргументов может быть разным, количество скармливаемых функции аргументов должно совпадать с количеством заявленных для функции параметров
Параметры в списке параметров функции разделяются запятыми и их может быть сколько угодно, хотя слишком много обычно никто нормальный не использует.
Из-за неявных приведений в языке С++ вы можете вызывать функции, в списке параметров которых типы не совсем соответствуют типам аргументов. Если тип аргумента может быть неявно приведён к типу, указанному в параметре, принимающем аргумент, то тогда вызов функции пройдёт успешно:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
//clang Знакомство с функциями Листинг #8
#include <iostream>
usingnamespacestd;
intsum(inta,intb){returna+b;}
intmain(){
doublevalue1=5.6;//Два значения
doublevalue2=6.7;//будут скормлены функции
cout<<sum(value1,value2)<<'\n';
}
Программист, написавший листинг #8, мог бы написать много кода и где-то недописать функцию с правильным списком параметров. А однажды, когда уже было бы поздно, и когда очень не нужно, могла всплыть допущенная им ошибка. Всмотритесь в код: программист задаёт два дробных числа и пытается их сложить, функция сложения успешно срабатывает, но результат её целое число. Это всё следствие неявных преобразований. Значения аргументов, уходящие в параметры функции преобразуются к типу, указанному в параметрах, происходит неявное приведение типа double к типу int, складываются два int и функция отдаёт int. Покольку тип для функции int, то отдаёт она значение с типом int, но в данном случае из-за типов списков параметров и типов приходящих в них аргументов, даже если бы функция отдавала double, это бы несильно изменило ситуацию, отдавалось бы округлённое до целого число, можете проверить, поменяв тип функции, оставив типы параметрам.
Если правила языка С++ допускают неявное преобразование типа аргумента к типу, заявленному в списке принимающего аргумент параметра, то параметр способен принимать такой аргумент
Правильнее бы было написать, например, две функции, обязательно задать им правильный тип. Обрщайте своё внимание на типы:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
usingnamespacestd;
intsum(inta,intb){
cout<<"sum integers\t ";
returna+b;
}
doublesum(doublea,doubleb){
cout<<"sum doubles\t ";
returna+b;
}
intmain(){
doublevalue1=5.6;//Два значения
doublevalue2=6.7;//будут скормлены функции
intvalue3=9;
intvalue4=10;
cout<<sum(value1,value2)<<'\n';
cout<<sum(value3,value4)<<'\n';
}
В таком случае срабатывает та функция, в которой типы приходящих аргументов в большй степени соответствуют типам принимающих их параметров. Если есть несколько функций с неполным соответствием в типах, но эти функции обе в одинаковой степени подходят под наилучший выбор компилятором, то компилятор словит неоднозначность выбора, т. е. не сможет выбрать наиболее подходящую функцию и будет на вас ругаться матом.
Предлагаю снова обратить вам ваш взор на показываемую ранее табличку:
ТИП
Название
Список параметров
Блок кода
int
main
()
{}
void
foo
()
{}
int
sum
(int a, int b)
{return a+b;}
double
sum
(double a, double b)
{return a+b;}
int
sum
(int a, int b, const char* S)
{
cout << S << '\n';
return a+b;
}
Вы можете попробовать создать простейший калькулятор, используя знания, полученные из этой статьи: создайте меню и несколько функций. На первый раз достаточно четырёх: сложение, вычитание, деление, умножение. В зависимости от выбранного пункта меню пользователем, вызывайте выбранную функцию. Для большего эффекта можете создать цикл, благодаря которому можно будет выполнять выбор много раз. К тому же можете попробовать сложить все результаты, полученные в ходе работы программы, для этого вам нужно будет использовать одномерный массив, в который запоминать получаемые значения, а потом, обходя массив использовать написанную вами функцию сложения двух чисел, пример которой описан в статье. Эта простая задача с длинным условием лучше поможет вам понять суть функций.
Подводим итоги:
Функции — это внутренние для программных нужд сущности-вычислители, производящие полезное действие или порождающие значение, получаемое путём вычисления
Язык С++ позволяет описывать функции в любом порядке (сверху-вниз, снизу вверх, смешанно), но некоторое время, в первые дни знакомства с функциями, пробуйте придерживаться стиля снизу-вверх
Функции состоят из 4 частей: тип, название, список формальных параметров, блок с вычислением
Если тип, приписанный к функции, не void, тогда внутри функции обязательно должно быть return (исключением является функция main(), современные компиляторы умеют неявно прописывать return внутри неё, поэтому в ней оно необязательно в явном виде)
Функциям можно давать любой тип, исключением является функция main(), тип которой обязан быть int
Круглые скобки функции — это список формальных параметров. При написании функции в список параметров надо заявить типы, с которыми должна работать функция, и дать параметрам имена, чтобы мы имели связь с параметрами, принимающими приходящие данные
Список формальных параметров может быть или пустым (пустые круглые скобки), или с заявленными параметрами
Количество параметров должно совпадать с количеством приходящих в функцию аргументов. Исключение только если в списке формальных параметров явно описано то, что количество приходящих в функцию аргументов может быть разным. Вам пока что нужно просто познакомиться с функциями и понять их суть, о разном количестве аргументов задумываться не нужно (не бегите впереди паровоза)
Типы параметров должны совпадать с типами приходящих в них аргументов. Хоть иногда типы могут совпадать не строго, из-за умения С++ неявно преобразовывать типы, лучше следовать простому правилу, что типы должны полносьтью совпадать, иначе можно словить не очень приятную ошибку
Количество параметров ничем не ограничено
Функции, порождающие значение путём использования в вычислении пришедших в них аргументов, могут отдавать результат вычисления, для этого используется return
В первое время функцию можно воспринимать как переменную, которой можно скормить значения, чтобы получить какой-то ожидаемый эффект: сумма, разность, квадратный корень, степень или логарифм и др. — любой запрограммированный прогаммистом или вами эффект. Но в то же время нужно помнить и никогда не забывать, что функции — не переменные. Этот совет только для вашего осознания способов использования функций в кодах. В функцию обычно нельзя присвоить значение, но забрать из функции значение как будто бы она переменная — легко.
Различайте термины аргумент и параметр. Аргументы используются при обращении к функции (возможно, множестов раз), а параметры в описании функции только однажды
Для понта. В таком коде они не имеют смысла.
Тем не менее, лучше использовать const везде, где он уместен (в смысле, где переменная не должна менять собственное значение, там везде должно быть const или volatilie). В оговариваемом листинге значения параметров не изменяются, поэтому.
Хоть непосредственно сейчас это не имеет смысла, но в случае развития кода может оказаться полезным.
В большинстве моих кодов const не использован, это для того, чтобы читаемость кода была лучше. Это неправильно с практической точки зрения. Но иначе бы весь сайт был напичкан страшно неудобными для новичка конструкциями в параметрах функций, эта не самая страшная.
спс
в последнем листинге зачем все время приписывать конст к типу?
Для понта. В таком коде они не имеют смысла.
Тем не менее, лучше использовать const везде, где он уместен (в смысле, где переменная не должна менять собственное значение, там везде должно быть const или volatilie). В оговариваемом листинге значения параметров не изменяются, поэтому.
Хоть непосредственно сейчас это не имеет смысла, но в случае развития кода может оказаться полезным.
В большинстве моих кодов const не использован, это для того, чтобы читаемость кода была лучше. Это неправильно с практической точки зрения. Но иначе бы весь сайт был напичкан страшно неудобными для новичка конструкциями в параметрах функций, эта не самая страшная.