Выбрать главу

НОД: 3

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

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

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( vectorint, int );

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

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

int[10] foo_bar();

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

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

int *foo_bar();

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

Функция может возвращать типы классов, в частности контейнеры. Например:

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

listchar foo_bar();

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

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

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

const is_equa1( vectorint vl, vectorint v2 );

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

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

const bool is_equa1( vectorint vl, vectorint v2 );

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

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

int fork();

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*?

cd( "hello", "world" );

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

gcd( 24312 );

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

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