Logo GenDocs.ru


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


Лекции по информатике - файл 1.doc


Лекции по информатике
скачать (1270.5 kb.)

Доступные файлы (1):

1.doc1271kb.16.11.2011 02:47скачать

содержание

1.doc

1   ...   5   6   7   8   9   10   11   12   ...   15
Реклама MarketGid:
^

Функции языка C++


Функции являются основной частью любой программы на С++. Именно они выполняют все необходимые действия. Функция - это именованная часть программы, к которой можно обращаться из других частей программы столько раз, сколько потребуется. Обычно с помощью функции реализуют какую-то законченную часть алгоритма.
^

Декларации и дефиниции функций


С использованием функций в языке СИ связаны три понятия - определение функции (описание действий, выполняемых функцией), объявление функции (задание формы обращения к функции) и вызов функции.

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


Заголовок_функции

{ тело_функции;

}


Заголовок_функции имеет следующий синтаксис:


тип_возвращаемого_функцией_значения имяФункции (СписокФормальныхПараметров)


тело_функции – это набор необходимых операторов, реализующий нужный алгоритм.

Обратите внимание! Тело функции всегда заключено в фигурные скобки – блок.


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

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


^ Декларация функции (прототип) – это ее заголовок с символом точка с запятой в конце.

Например, обе декларации идентичны:


void my_func (void);

void my_func ();


Функция имеет имя my_func, не имеет формальных параметров и ничего не возвращает.


Замечание! Если декларация функции записана следующим образом:

my_func (void);

то функция по умолчанию возвращает значение типа int.


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

Если объявление функции не задано, то по умолчанию строится прототип функции на основе анализа первой ссылки на функцию, будь то вызов функции или определение. Однако такой прототип не всегда согласуется с последующим определением или вызовом функции. Рекомендуется всегда задавать прототип функции. Это позволит компилятору либо выдавать диагностические сообщения, при неправильном использовании функции, либо корректным образом регулировать несоответствие аргументов устанавливаемое при выполнении программы.


Дефиниция функции – это полная запись функции с заголовком (но БЕЗ точки с запятой!) и телом.

^

Формальные и фактические параметры. Вызов функций


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

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

В наших примерах функций my_func и pause пока нет ни формальных, ни фактических параметров. Вызовы таких функций имеют вид:


my_func();

pause();


Обратите внимание! Служебное слово типа данных здесь НЕ пишется НИКОГДА!

В простейших случаях количество и тип фактических параметров должен совпадать с количеством и типом формальных.
^

Возврат функцией значений


Очень часто от функции требуется, чтобы она не только выполняла определенную работу (например, вывод сообщения с помощью printf), но и возвращала результат вычислений в вызывающую функцию. Для обеспечения возврата результата в вызывающий код в функции должен использоваться оператор return, который имеет следующий формат:


return(result);


Тип функции определяет тип возвращаемого ею значения (int,float, char и т.д.). Например, если функция возвращает значение типа int, то имени функции должно предшествовать то же самое имя типа:


int some_function(int value)

{

// Оператор функции

}


Следующая функция i_cube возвращает куб от целого значения, определенного в качестве параметра. Например, если в функцию передается 5, то i_cube будет возвращать значение равное 5*5*5 или 125:


int i_cube (int value)

{

return(value * value * value);

}


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


result = i_cube(5);


printf("Kyб от 5 равен %d\n", i_cube(5));


Если функция должна возвращать значение другого типа (float, double, char и т.д.), то этот тип необходимо задавать при объявлении функции. В следующей программе функция average_value используется для вычисления среднего арифметического трех значений типа int. При этом значение, которое возвращается функцией, имеет тип float:


#include <stdio.h>


float average_value(int a, int b, int c)

{

return ((a + b + с) / 3.0);

}


void main(void)

{

printf("Среднее от 100, 133 и 155 равно %f\n",

average_value(100, 133, 155));

}


Как можно видеть, тип возвращаемого функцией значения определяется в заголовке функции:


float average_value(int a, int b, int с)


Примечание: Если компилятору не сообщается тип возвращаемого функцией значения, то в качестве такового по умолчанию считается int.

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


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


void my_function (int age, char *name);


Если в дальнейшем в программе будет предпринята попытка использовать значение функции

result = my_function (32, "Jamsa");


то компилятор выдаст ошибку.
^

Переменные в функциях


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

Автоматические (локальные) переменные


Некоторые функции нуждаются в собственных переменных и константах.

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

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

Например, в следующей функции use_abc объявляется три локальные переменные a, b и с:


void use_abc(void)

{

int a, b, с;


а=3;

b=а+1;

с = а + b;


printf("a содержит %d b содержит %d с содержит %d\n ", а, b, с);

}

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

^

Внешние (глобальные) переменные


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


int temp;

main()


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


main()

{

printf("Введите значение температуры: ");

scanf("%d", &temp);

convert();

freeze();

boil();

}

convert()

{

float celsius;

celsius = (5.0 / 9.0) * (temp - 32);

printf("%d градусов по шкале Фаренгейта

соответствует %6.2f градусам \

по шкале Цельсия\n", temp, celsius);

return(0);

}

freeze()

{

printf("Это составляет %d градусов

от точки замерзания воды\n", temp-32);

return(0);

}


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


#include <stdio.h>


void unknown_title(void)

{

printf("Название книги %s\n ", title);

}

char title[] = "1001 совет по C/C++";


void main(void)

{

printf("Название: %s\n", title);

}

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

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

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

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

Статические переменные


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

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

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


myfunc()

{

static int count;

}


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

^

Передача параметров по значению


Когда параметр передается в функцию, по умолчанию используется техника, известная как передача параметра по значению, при которой функция обеспечивается копией значения параметра. При передаче параметра по значению любые изменения, выполняемые в функции над значением данного параметра, существуют только внутри самой функции. Когда функция завершается, значение переменной, переданной по значению, оказывается не измененным. Например, в следующей программе функции display_and_change передаются три параметра (переменные a, b и с):


#include <stdio.h>


void display_and_change(int first, int second, int third)

{

printf("Начальные значения функции %d %d %d\n",

first, second, third);


first += 100;

second +=100;

third += 100;


printf("Конечные значения функции %d %d %d\n",

first, second, third);

}


void main(void)

{

int a=l, b=2, с = 3;


display_and_change(a, b, c);


printf("Конечные значения main %d %d %d\n", a, b ,c);

}


После компиляции и выполнения программы на экран выводится:


C:\> NOCHANGE <ЕNTER>

Начальные значения функции 123

Конечные значения функции 101 102 103

Конечные значения main 123


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

При передаче параметров в функцию их значения размещаются в стеке. Для случая переменных a, b и с в стеке будут содержаться значения 1,2 и 3 соответственно. Любые изменения, выполняемые в функции над значениями параметров, в действительности изменяют значения ячеек стека.

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



^

Передача параметров по ссылке


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

Для того чтобы функция могла возвращать модифицированное значение своего параметра, при вызове такой функции должен использоваться способ, называемый передача параметра по ссылке. Различие между передачей параметра по значению и по ссылке заключается в том, что в первом случае функция получает копию значения параметра, а во втором - адрес значения переменной. Таким образом, при получении параметра по ссылке функция может производить изменения значения, сохраненного по данному адресу, и эти изменения остаются в силе и после завершения функции. Для организации передачи параметров функции по ссылке в программе должны использоваться указатели. Подробно этот тип переменных обсуждается в разделе "Массивы, указатели и структуры". Здесь же будем рассматривать указатель просто как адрес памяти. Для присваивания указателю адреса переменной используется операция получения адреса (&). Для доступа к значению, расположенному по месту памяти, задаваемому указателем, применяется операция "звездочка" (*).


int x;

int &y=x;


Идентификатор y назначает другое, альтернативное имя ячейке, названной x. Если прибавить к значению переменной x некоторое число, то оно будет прибавлено и к переменной y.


#include <iostream.h>

#include <conio.h>

void summa(int &number1, int &number2)

{

number1++;

number2++;

}

void main()

{

int a=10;

int b=15;

cout<<"Before upd "<<a<<" "<<b;

summa(a,b);

cout<<"\nAfter upd "<<a<<" "<<b;

getch();

}


Результат

Before upd 10 15

After upd 11 16


Так как number1 и a – это одна и та же ячейка, то изменение number1 автоматически приведет к изменению переменной a (аналогично number2 и b).

^

Значения параметров по умолчанию


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

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


void some_function(int size=12, float cost=19.95) //--->Значения по умолчанию

{
   // Операторы функции
}


Следующая программа присваивает значения по умолчанию параметрам a, b и c внутри функции show_parameters. Затем программа четыре раза вызывает эту функцию, сначала не указывая параметров вообще, затем указывая значение только для а, потом значения для а и b и, наконец, указывая значения для всех трех параметров:


#include <iostream.h>

void show__parameters (int a=1, int b=2, int c=3)

{
   cout << "a" << a << " b " << b << " с " << с << endl;
}

void main(void)

{
   show_parameters();
   show_parameters(1001);
   show_parameters(1001, 2002);
   show_parameters(1001, 2002, 3003);
}


Когда вы откомпилируете и запустите эту программу, на вашем экране появится следующий вывод:


С:\> DEFAULTS <ENTER>

а 1 b 2 с 3

а 1001 b 2 с 3

а 1001 b 2002 с 3

а 1001 b 2002 с 3003


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


^ Правила для пропуска значений параметров

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


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


int my_function(void);


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

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


При определении функций в своих программах вы должны указать тип возвращаемого функцией значения, а также количество параметров и тип каждого из них. При программировании на языке С, когда у вас была функция, например, с именем add_values, которая работала с двумя целыми значениями, а вы хотели бы использовать подобную функцию для сложения трех целых значений, вам следовало создать функцию с другим именем. Например, вы могли бы использовать add_two_values и add_three_values. Аналогично если вы хотели использовать подобную функцию для сложения значений типа float, то вам была бы необходима еще одна функция с еще одним именем. Чтобы избежать дублирования функции, C++ позволяет вам определять несколько функций с одним и тем же именем. В процессе компиляции C++ принимает во внимание количество аргументов, используемых каждой функцией, и затем вызывает именно требуемую функцию. Предоставление компилятору выбора среди нескольких функций называется перегрузкой.

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

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

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


#include <iostream.h>

int add_values(int a,int b)

{
   return(a + b);
)

int add_values (int a, int b, int c)

(
   return(a + b + c);
)

void main(void)

{
   cout << "200 + 801 = " << add_values(200, 801) << endl;
   cout << "100 + 201 + 700 = " << add_values(100, 201, 700) << endl;
}


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

Одним из наиболее общих случаев использования перегрузки является применение функции для получения определенного результата, исходя из различных параметров. Например, предположим, что в вашей программе есть функция с именем day_of_week, которая возвращает текущий день недели (0 для воскресенья, 1 для понедельника, ..., 6 для субботы). Ваша программа могла бы перегрузить эту функцию таким образом, чтобы она верно возвращала день недели, если ей передан юлианский день в качестве параметра, или если ей переданы день, месяц и год:


int day_of_week(int julian_day)

{
   // Операторы
}

int day_of_week(int month, int day, int year)

{
   // Операторы
}

Рекурсия


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

Рекурсивной функцией называется функция, которая для выполнения определенной операции вызывает саму себя. Процесс вызова функцией самой себя называется рекурсией. По мере возрастания сложности программ и функций может оказаться, что при определении некоторых операций удобно использовать сами эти операции. В таких случаях имеет смысл создавать рекурсивные функции. Классическим примером рекурсивной обработки является вычисление факториала. Факториал значения 1 равен 1. Факториал значения 2 равен 2*1. Факториал значения 3 равен 3*2*1. Аналогично, факториал значения 4 равен 4*3*2*1. Этот процесс может быть продолжен до бесконечности. Если внимательно приглядеться к процессу вычисления факториала, то можно увидеть, что факториал, например, от 4 равен 4-кратному значению факториала от 3 (3*2*1). Аналогично, факториал от 3 равен 3-кратному значению факториала от 2 (2*1). Факториал от 2 равен двукратному значению факториала от 1 (1). В таблице демонстрируется вычисление факториала.


Таблица. Вычисление факториала

Значение

Вычисление

Результат

Факториал

1

1

1

1

2

2*1

2

2*Factorial(l)

3

3*2*1

6

3* Factorial(2)

4

4*3*2*1

24

4* Factorial(3)

5

5*4*3*2*1

120

5* Factorial(4)


В следующей программе представлена рекурсивная функция factorial, которая используется для вычисления факториала значений от 1 до 5:


#include <stdio.h>


int factorial (int value)

{

if (value ==1)

return(1);

else

return(value * factorial(value-1));

}


void main(void)

{

int i;

for (i =1; i <= 5; i++)

printf("Факториал от %d равен %d\n", i, factorial(i));

}


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

При выполнении этой функции первым делом осуществляется проверка значения параметра на равенство 1. Если значение равно 1, то функция возвращает 1. В противном случае, в качестве результата возвращается значение, равное произведению значения входного параметра и факториала от числа, равного значению параметра минус 1. Например, предположим, что функция вызывается со значением 3. Тогда в качестве результата функцией будет возвращено 3*factorial(3-1). Обнаруживая в операторе return вызов функции factorial, компилятор организует повторный вызов, на этот раз со значением 3-1 или 2. Поскольку значение не равно 1, результатом выполнения функции будет 2*factorial(2-1). Наконец, при следующем вызове функции значение параметра равно 1, поэтому в качестве результата вызвавшей программе (функции) возвращается значение 1.

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

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

^

Встроенные функции


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

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

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

Когда вы определяете в своей программе функцию, компилятор C++ переводит код функции в машинный язык, сохраняя только одну копию инструкций функции внутри вашей программы. Каждый раз, когда ваша программа вызывает функцию, компилятор C++ помещает в программу специальные инструкции, которые заносят параметры функции в стек и затем выполняют переход к инструкциям этой функции. Когда операторы функции завершаются, выполнение программы продолжается с первого оператора, который следует за вызовом функции. Помещение аргументов в стек и переход в функцию и из нее вносит издержки, из-за которых ваша программа выполняется немного медленнее, чем если бы она размещала те же операторы прямо внутри программы при каждой ссылке на функцию. Например, предположим, что следующая программа CALLBEEP.CPP вызывает функцию show_message, которая указанное число раз выдает сигнал на динамик компьютера и затем выводит сообщение на дисплей:


#include <iostream.b>

void show_message(int count, char *message)

{
   int i;
   for (i = 0; i < count; i++) cout << '\a';
   cout << message << endl;
}

void main(void)

{
   show_message(3, "Учимся программировать на языке C++");
   show_mes sage(2, "Встроенные функции");
}


Следующая программа NO_CALL.CPP не вызывает функцию show_message. Вместо этого она помещает внутри себя те же операторы функции при каждой ссылке на функцию:


#include <iostream.h>

void main (void)

{
   int i;
   for (i = 0; i < 3; i++) cout << '\a';
   cout << " Учимся программировать на языке C++" << endl;
   for (i = 0; i < 2; i++) cout << '\a';
   cout << " Встроенные функции " << endl;
}


Обе программы выполняют одно и то же. Поскольку программа NO_CALL не вызывает функцию show_message, она выполняется немного быстрее, чем программа CALLBEEP. В данном случае разницу во времени выполнения определить невозможно, но, если в обычной ситуации функция будет вызываться 1000 раз, вы, вероятно, заметите небольшое увеличение производительности. Однако программа NO_CALL более запутана, чем ее двойник CALL_BEEP, следовательно, более тяжела для восприятия.

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


^ Использование ключевого слова inline

При объявлении функции внутри программы C++ позволяет вам предварить имя функции ключевым словом inline. Если компилятор C++ встречает ключевое слово inline, он помещает в выполнимый файл (машинный язык) операторы этой функции в месте каждого ее вызова. Таким образом, можно улучшить читаемость ваших программ на C++, используя функции, и в то же время увеличить производительность, избегая издержек на вызов функций. Следующая программа INLINE.CPP определяет функции тах и min как inline:


#include <iostream.h>

inline int max(int a, int b)

{
   if (a > b) return(a);
   else return(b) ;
}

inline int min(int a, int b)

{
   if (a < b) return(a);
   else return(b);
}

void main(void)

{
   cout << "Минимум из 1001 и 2002 равен " << min(1001, 2002) << endl;
   cout << "Максимум из 1001 и 2002 равен " << max(1001, 2002) << endl;
}


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

1   ...   5   6   7   8   9   10   11   12   ...   15

Реклама:





Скачать файл (1270.5 kb.)

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

© gendocs.ru
При копировании укажите ссылку.
обратиться к администрации
Рейтинг@Mail.ru