Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих.pdf
Скачиваний:
183
Добавлен:
01.05.2014
Размер:
3.97 Mб
Скачать

int abs( int ); int min( int,

int ); int gcd( int, int );

(В таком объявлении можно не указывать имя параметра, ограничиваясь названием типа.)

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

// определение функции находится в файле gcd.С

int gcd( int, int );

inline int abs(int i) { return( i<0 ? -i : i );

}

inline int min(int vl.int v2) { return( vl<v2 ? vl : v2 );

заголовочный файл для нашего примера. Назовем его localMath.h:

}

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

При выполнении наша программа main.C, получив от пользователя значения:

Введите первое значение: 15 Введите второе значение: 123

выдаст следующий результат:

mm: 15 НОД: 3

7.2. Прототип функции

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

17 Таким образом, как мы видим, определения встроенных функций могут встретиться в программе несколько раз! – Прим. ред.

7.2.1. Тип возвращаемого функцией значения

Тип возвращаемого функцией значения бывает встроенным, как int или double, составным, как int& или double*, или определенным пользователем – перечислением или классом. Можно также использовать специальное ключевое слово void, которое

#include <string>

#include <vector> class Date { /* определение */ };

bool look_up( int *, int ); double calc( double );

int count( const string &, char ); Date& calendar( const char );

говорит о том, что функция не возвращает никакого значения: void sum( vector<int>&, int );

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

// массив не может быть типом возвращаемого значения

Следующий пример ошибочен: int[10] foo_bar();

// правильно: указатель на первый элемент массива

Но можно вернуть указатель на первый элемент массива: int *foo_bar();

(Размер массива должен быть известен вызывающей программе.)

// правильно: возвращается список символов

Функция может возвращать типы классов, в частности контейнеры. Например: list<char> foo_bar();

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

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

// ошибка: пропущен тип возвращаемого значения

код вызывает ошибку компиляции:

const is_equa1( vector<int> vl, vector<int> v2 );

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

// правильно: тип возвращаемого значения указан

is_equal() выглядит так:

const bool is_equa1( vector<int> vl, vector<int> v2 );

7.2.2. Список параметров функции

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

int

f o r k

(

)

;

Например, следующие объявления эквивалентны: int fork( void );

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

int manip( int vl, v2 );

//

ошибка

 

параметрами:

int manip( int vl, int v2 ); // правильно

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

void print( int *array, int size );

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

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

7.2.3. Проверка типов формальных параметров

Функция gcd() объявлена следующим образом:

int gcd( int, int );

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

Что будет, если попытаться вызвать функцию gcd() с аргументами типа char*?

gcd( "hello", "world" );

А если передать этой функции не два аргумента, а только один? Или больше двух? Что случится, если потеряется запятая между числами 24 и 312?

gcd( 24312 );

Единственное разумное поведение компилятора – сообщение об ошибке, поскольку попытка выполнить такую программу чревата весьма серьезными последствиями. С++ действительно не пропустит подобные вызовы. Текст сообщения будет выглядеть примерно так:

// gcd( "hello", "world" )

error: invalid argument types ( const char *, const char * ) -- expecting ( int, int )

ошибка: неверные типы аргументов ( const char *, const char * ) -- ожидается ( int, int )

// gcd( 24312 )

error: missing value for second argument ошибка: пропущено значение второго аргумента

А если вызвать эту функцию с аргументами типа double? Должен ли этот вызов расцениваться как ошибочный?

gcd( 3.14, 6.29 );

Как было сказано в разделе 4.14, значение типа double может быть преобразовано в int. Следовательно, считать такой вызов ошибочным было бы слишком сурово. Вместо этого аргументы неявно преобразуются в int (отбрасыванием дробной части) и таким образом требования, налагаемые на типы параметров, выполняются. Поскольку при подобном преобразовании возможна потеря точности, хороший компилятор выдаст предупреждение. Вызов превращается в

gcd( 3, 6 );

что дает в результате 3.

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