Чтение онлайн

ЖАНРЫ

Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:

Указатель на функцию (см. раздел 27.2.5) можно только копировать и вызывать. Рассмотрим пример.

typedef void (*Handle_type)(int);

void my_handler(int);

Handle_type handle = my_handler;

handle(10); // эквивалент my_handler(10)

A.8.2. Массивы

Массив (array) — это неразрывная последовательность объектов (элементов) одинакового типа, имеющая фиксированную длину.

int a[10]; // 10
целых чисел

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

a[7]
равно
0
. Если массив является локальным (переменная объявлена в функции) или создан с помощью оператора
new
, то элементы встроенных типов останутся неинициализированными, а элементы, имеющие пользовательский тип, будут инициализированы его конструкторами.

Имя массива неявно преобразуется в указатель на его первый элемент. Рассмотрим пример.

int* p = a; // указатель p ссылается на элемент a[0]

Массив или указатель на элемент массива может индексироваться с помощью оператора

[]
. Рассмотрим пример.

a[7] = 9;

int xx = p[6];

Элементы массива нумеруются начиная с нуля (разделы 18.5).

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

vector
. Размер массива — это сумма размеров его элементов. Рассмотрим пример.

int a[max]; // sizeof(a) == sizeof(int)*max

Можно определить и использовать массив массивов (двумерный массив), массив массивов массивов (многомерный массив) и т.д. Рассмотрим пример.

double da[100][200][300]; // 300 элементов типа, состоящего из

da[7][9][11] = 0;

Нетривиальное использование многомерных массивов — тонкое и уязвимое для ошибок дело (см. раздел 24.4). Если у вас есть выбор, следует предпочесть класс

Matrix
(как в главе 24).

A.8.3. Ссылки

Ссылка (reference) — это синоним (alias), т.е. альтернативное имя объекта.

int a = 7;

int& r = a;

r = 8; // переменная a становится равной 8

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

void f(const string& s);

// ...

f("эту строку слишком дорого копировать, \\

поэтому используется ссылка");

См. разделы 8.5.4–8.5.6.

A.9. Функции

Функция (function) — это именованный фрагмент кода, получающий (возможно, пустой) набор аргументов

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

char f(string, int);

Итак,

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

char f(string s, int i) { return s[i]; }

Телом функции должен быть блок (см. раздел 8.2) или блок

try
(см. раздел 5.6.3).

Функция, в объявлении которой указано, что она возвращает какое-то значение, должна его возвращать (используя оператор

return
).

char f(string s, int i) { char c = s[i]; } // ошибка: ничего

// не возвращается

Функция

main
представляет собой странное исключение из этого правила (см. раздел A.1.2). За исключением функции
main
, если не хотите возвращать значение, то поставьте перед именем функции ключевое слово
void
. Другими словами, используйте слово
void
как тип возвращаемого значения.

void increment(int& x) { ++x; } // OK: возвращать значение

// не требуется

Функция вызывается с помощью оператора вызова

с соответствующим списком аргументов.

char x1 = f(1,2); // ошибка: первый аргумент функции f должен

// быть строкой

string s = "Battle of Hastings";

char x2 = f(s); // ошибка: функция f требует двух аргументов

char x3 = f(s,2); // OK

Более подробную информацию о функциях см. в главе 8.

A.9.1. Разрешение перегрузки

Разрешение перегрузки (overload resolution) — это процесс выбора функции для вызова на основе набора аргументов. Рассмотрим пример.

void print(int);

void print(double);

void print(const std::string&);

print(123); // вызывается print(int)

print(1.23); // вызывается print(double)

print("123"); // вызывается print(const string&)

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

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

Поделиться с друзьями: