Категории
Самые читаемые
Лучшие книги » Компьютеры и Интернет » Программирование » Язык программирования C++. Пятое издание - Стенли Липпман

Язык программирования C++. Пятое издание - Стенли Липпман

Читать онлайн Язык программирования C++. Пятое издание - Стенли Липпман

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 75 76 77 78 79 80 81 82 83 ... 297
Перейти на страницу:

int arr[10];          // arr массив из десяти целых чисел

int *p1[10];          // p1 массив из десяти указателей

int (*p2)[10] = &arr; // p2 указывает на массив из десяти целых чисел

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

Тип (*функция(список_параметров))[размерность]

Как и в любом другом объявлении массива, Тип — это тип элементов, а размерность — это размер массива. Круглые скобки вокруг части (*функция(список_параметров)) необходимы по той же причине, по которой они были нужны при определили указателя p2. Без них мы определили бы функцию, которая возвращает массив указателей.

В качестве конкретного примера рассмотрим следующее объявление функции func(), не использующей псевдоним типа:

int (*func(int i))[10];

Чтобы понять это объявление, имеет смысл прочитать его следующим образом:

• func(int) указывает, что функцию func() можно вызвать с аргументом типа int;

• (*func(int)) указывает, что можно обратиться к значению результата этого вызова;

• (*func(int))[10] указывает, что обращение к значению результата вызова функции func() возвращает массив из десяти элементов;

• int (*func(int))[10] указывает, что типом элементов этого массива является int.

Использование замыкающего типа возвращаемого значения

По новому стандарту есть и другой способ упростить объявления функции func() — с использованием замыкающего типа возвращаемого значения (trailing return type). Оно может быть определено для любой функции, но полезней всего оно для функций со сложными типами возвращаемого значения, такими как указатели (или ссылки) на массивы. Замыкающий тип возвращаемого значения следует за списком параметров и предваряется символом ->. Чтобы сообщить о том, что возвращаемое значение следует за списком параметров, ключевое слово auto располагается там, где обычно присутствует тип возвращаемого значения:

// fcn получает аргумент типа int и возвращает указатель на массив

// из десяти целых чисел

auto func(int i) -> int(*)[10];

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

Использование спецификатора decltype

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

int odd[] = {1,3,5,7,9};

int even[] = {0,2,4,6,8};

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

decltype(odd) *arrPtr(int i) {

 return (i % 2) ? &odd : &even; // возвращает указатель на массив

}

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

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

Упражнения раздела 6.3.3

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

Упражнение 6.37. Напишите три дополнительных объявления для функций предыдущего упражнения. Нужно использовать псевдоним типа, замыкающий тип возвращаемого значения и спецификатор decltype. Какую форму вы предпочитаете и почему?

Упражнение 6.38. Перепишите функцию arrPtr() так, чтобы она возвращала ссылку на массив.

6.4. Перегруженные функции

Функции, расположенные в одной области видимости, называются перегруженными (overloaded), если они имеют одинаковые имена, но разные списки параметров. Пример определения нескольких функций по имени print() приведен в разделе 6.2.4:

void print(const char *cp);

void print(const int *beg, const int *end);

void print(const int ia[], size_t size);

Эти функции выполняют одинаковое действие, но их параметры относятся к разным типам. При вызове такой функции компилятор принимает решение о применении конкретной версии на основании типа переданного аргумента:

int j[2] = {0, 1};

print("Hello World");        // вызов print (const char*)

print(j, end(j) - begin(j)); // вызов print(const int*, size_t)

print(begin(j), end(j));     // вызов print(const int*, const int*)

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

Функция main() не может быть перегружена.

Определение перегруженных функций

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

Record lookup(const Account&); // поиск по счету

Record lookup(const Phone&);   // поиск по телефону

Record lookup(const Name&);    // поиск по имени

Account acct;

Phone phone;

Record r1 = lookup(acct);  // вызов версии, получающей Account

Record r2 = lookup(phone); // вызов версии, получающей Phone

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

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

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

Record lookup(const Account&);

bool lookup(const Account&); // ошибка: отличается только типом

                             // возвращаемого значения

Различие типов параметров

Два списка параметров могут быть идентичными, даже если они не выглядят одинаково:

// каждая пара объявляет ту же функцию

Record lookup(const Account &acct);

Record lookup(const Account&); // имена параметров игнорируются

typedef Phone Telno;

Record lookup(const Phone&);

Record lookup(const Telno&);   // Telno и Phone того же типа

Первое объявление в первой паре именует свой параметр. Имена параметров предназначены только для документирования. Они не изменяют список параметров.

Во второй паре типы только выглядят разными, Telno — не новый тип, это только синоним типа Phone. Псевдоним типа (см. раздел 2.5.1) предоставляет альтернативное имя для уже существующего типа, а не создает новый тип. Поэтому два параметра, отличающиеся только тем, что один использует имя типа, а другой его псевдоним, не являются разными.

Перегрузка и константные параметры

Как упоминалось в разделе 6.2.3, спецификатор const верхнего уровня (см. раздел 2.4.3) никак не влияет на объекты, которые могут быть переданы функции. Параметр, у которого есть спецификатор const верхнего уровня, неотличим от такового без спецификатора const верхнего уровня:

Record lookup(Phone);

1 ... 75 76 77 78 79 80 81 82 83 ... 297
Перейти на страницу:
На этой странице вы можете бесплатно скачать Язык программирования C++. Пятое издание - Стенли Липпман торрент бесплатно.
Комментарии