Можно также обращаться к элементам матрицы, используя схему их размещения в памяти, т.е. через указатель на ее первый элемент.
int* p = a.data(); // извлекаем данные с помощью указателя на массив
Это полезно при передаче объектов класса Matrix
функциям в стиле языка C, принимающим указатели в качестве аргументов. Матрицы можно индексировать.
a(i); // i-й элемент (в стиле языка Fortran) с проверкой
// диапазона
a[i]; // i-й элемент (в стиле языка C) с проверкой диапазона
a(1,2); // ошибка: a — одномерный объект класса Matrix
Многие алгоритмы обращаются к части объекта класса Matrix
. Эта часть называется срезкой и создается функцией slice()
(часть объекта класса Matrix
или диапазон элементов). В классе Matrix
есть два варианта этой функции.
a.slice(i); // элементы, начиная с a[i] и заканчивая последним
a.slice(i,n); // n элементов, начиная с a[i] и заканчивая a[i+n–1]
Индексы и срезки можно использовать как в левой части оператора присваивания, так и в правой. Они ссылаются на элементы объекта класса Matrix
, не создавая их копии. Рассмотрим пример.
a.slice(4,4) = a.slice(0,4); // присваиваем первую половину матрицы
// второй
Например, если объект a вначале выглядел так:
{ 1 2 3 4 5 6 7 8 }
то получим
{ 1 2 3 4 1 2 3 4 }
Обратите внимание на то, что чаще всего срезки задаются начальными и последними элементами объекта класса Matrix
; т.е. a.slice(0,j)
— это диапазон [0:j]
, а a.slice(j)
— диапазон [j:a.size()]
. В частности, приведенный выше пример можно легко переписать:
a.slice(4) = a.slice(0,4); // присваиваем первую половину матрицы
// второй
Иначе говоря, обозначения — дело вкуса. Вы можете указать такие индексы i
и n
, так что a.slice(i,n)
выйдет за пределы диапазона матрицы a
. Однако полученная срезка будет содержать только те элементы, которые действительно принадлежат объекту a
. Например, срезка a.slice(i,a.size())
означает диапазон [i:a.size()]
, а a.slice(a.size())
и a.slice(a.size(),2)
— это пустые объекты класса Matrix
. Это оказывается полезным во многих алгоритмах. Мы подсмотрели это обозначение в математических текстах. Очевидно, что срезка a.slice(i,0)
является пустым объектом класса Matrix
. Нам не следовало бы писать это намеренно, но существуют алгоритмы, которые становятся проще, если срезка a.slice(i,n)
при параметре n
, равном 0
, является пустой матрицей (это позволяет избежать ошибки).
Matrix
a = a2; // копирующее присваивание
Matrix
можно применять встроенные операции.
a *= 7; // пересчет: a[i]*=7 для каждого i (кроме того, +=, –=, /=
// и т.д.)
a = 7; // a[i]=7 для каждого i
Это относится к каждому оператору присваивания и каждому составному оператору присваивания (=
, +=
, –=
, /=
, *=
, %=
, ^=
, &=
, |=
, >>=
, <<=
) при условии, что тип элемента поддерживает соответствующий оператор. Кроме того, к каждому элементу объекта класса Matrix
можно применять функции.
a.apply(f); // a[i]=f(a[i]) для каждого элемента a[i]
a.apply(f,7); // a[i]=f(a[i],7) для каждого элемента a[i]
Составные операторы присваивания и функция apply()
модифицируют свои аргументы типа Matrix
. Если же мы захотим создать новый объект класса Matrix
, то можем выполнить следующую инструкцию:
b = apply(abs,a); // создаем новый объект класса Matrix
// с условием b(i)==abs(a(i))
Функция abs
— это стандартная функция вычисления абсолютной величины (раздел 24.8). По существу, функция apply(f,x)
связана с функцией x.apply(f)
точно так же, как оператор +
связан с оператором +=
. Рассмотрим пример.
b = a*7; // b[i] = a[i]*7 для каждого i
a *= 7; // a[i] = a[i]*7 для каждого i
y = apply(f,x); // y[i] = f(x[i]) для каждого i