На этом шаге мы продолжим рассматривать использование ссылок.
Гораздо большими возможностями, чем ссылки на функции, обладают ссылки, формируемые как возвращаемый результат выполнения функции. Рассмотрим следующую программу:
//RAZN5_1.СРР - ссылка и указатель на функцию. #include <iostream.h> // Функция определяет ссылку на элемент массива //с максимальным значением: int& rmax(int n, int d[]) { int im = 0; for (int i = 1; i < n; i++) im = d[im] > d[i] ? im : i; return d[im]; } void main() { int n = 4; int x[] = { 10, 20, 30, 14 }; cout << "\nrmax(n,x) = " << rmax(n,x); rmax(n,x) = 0; for (int i = 0; i < n; i++) cout << " x[" << i <<"] = " << x[i]; }
Результат выполнения программы:
rmax(n,x) = 30 x[0] = 10 x[l] = 20 x[2] = 0 x[3] = 14
В программе дважды используется обращение к rmax(). Один из вызовов находится в левой части оператора присваивания, что было бы совершенно недопустимо для языка С. С его помощью заносится нулевое значение в элемент x[2], вначале равный 30.
Возвращение функцией ссылки позволяет организовать многократное вложенное обращение к нескольким функциям. В результате таких вложенных обращений один и тот же объект можно многократно изменять по разным законам.
//RAZN5_2.СРР - вложенные вызовы функций, возвращающих ссылки. #include <iostream.h> // Функция возводит в куб значение параметра и возвращает // его адрес: double& rcube(double& z) { z=z*z*z; return z; } // Функция изменяет знак параметра и возвращает его адрес: double& rinvert(double& d) { d = -d; return d; } // Функция возвращает адрес параметра с максимальным значением: double& rmax(double& x, double& y) { return x > y ? x : y; } // Функция печатает значение параметра и возвращает его адрес: double& rprint (char* name, double& e) { cout << name << e; return e; } void main() { double a = 10.0, b = 8.0; rprint("\nrcube (rinvert (rmax (a,b))) = ", rcube(rinvert(rmax(a,b)))) = 0.0; cout << "\na = " << a << ",\tb = " << b; rcube(rinvert(rmax(a,b))) = 0.0; cout << "\na = " << a << ",\tb = " << b; }
Результат выполнения программы:
rcube (rinvert (rmax (a,b))) = -1000 a = 0, b = 8 a = 0, b = 0
Присваивание rprint() = 0.0 позволяет по цепочке передать нулевое значение аргументам функций и изменяет значение того из аргументов (а) функции rmax(), который вначале был максимальным. Последующее присваивание rcube() = 0.0 обнуляет значение параметра b.
В следующей программе введены две функции, возвращающие ссылки на элементы двухмерных массивов с изменяемыми размерами. Функция elem() позволяет по заданным значениям индексов "добираться" до конкретного элемента. Особого выигрыша применение такой функции не дает, она еще раз иллюстрирует возможности функций, возвращающих значения ссылок. Функция maxelem() возвращает адрес (ссылку) максимального элемента двумерного массива. Используя ее в левой части оператора присваивания, можно заменить значение максимального элемента. Именно это и выполняется в цикле основной программы. Результаты ее работы и комментарии в тексте поясняют сказанное. Текст программы:
//RAZN5_3.СРР - ссылки на элементы "двухмерных" массивов. #include <iostream.h> // Функция возвращает ссылку на обозначенный элемент матрицы: float& elem(float **matr, int k, int l) { return matr[k][l]; } // Функция заполняет матрицу значениями от 1 до 9: void matrix(int n, int m, float **pmatr) { int k = 0; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) elem(pmatr,i,j) = k++ % 9 + 1; } // Функция выбирает адрес максимального элемента матрицы: float& maxelem(int n, int m, float **pmatr) { int im = 0, jm = 0; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) { if (pmatr[im][jm] >= pmatr[i] [j]) continue; im = i; jm = j; } return pmatr[im][jm]; } // Функция печатает матрицу по строкам: void matr_print(int n, int m, float **pmatr) { for (int i = 0; i < n; i++) // Цикл перебора строк. { cout << "\n строка " << (i + 1) << ":"; // Цикл печати элементов строки: for (int j = 0; j < m; j++) cout << "\t" << pmatr[i][j]; } } void main () { float z[3][4]; float *ptr[] = { (float *)&z[0], (float *)&z[1], (float *)&z[2] }; matrix(3,4,ptr); // Заполняем матрицу. matr_print(3,4,ptr); // Печать исходной матрицы. for (int i = 0; i < 4; i++) // Обнулим 4 максимальных maxelem(3,4,ptr) =0.0; // элемента. matr_print(3,4,ptr); // Печать измененной матрицы. }
Результат выполнения программы:
строка 1: 1 2 3 4 строка 2: 5 6 7 8 строка 3: 9 1 2 3 строка 1: 1 2 3 4 строка 2: 5 0 0 0 строка 3: 0 1 2 3
На следующем шаге мы рассмотрим перегрузку функций.