Литмир - Электронная Библиотека
A
A

void init(Matrix<int,2>& a) // инициализация каждого элемента

                            // характеристическим значением

{

  for (int i=0; i<a.dim1(); ++i)

    for (int j = 0; j<a.dim2(); ++j)

      a(i,j) = 10*i+j;

}

void print(const Matrix<int,2>& a) // вывод элементов построчно

{

  for (int i=0; i<a.dim1(); ++i) {

    for (int j = 0; j<a.dim2(); ++j)

      cout << a(i,j) <<'\t';

    cout << '\n';

  }

}

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Итак,
dim1()
— это количество элементов в первой размерности,
dim2()
— количество элементов во второй размерности и т.д. Тип элементов и количество размерностей являются частью класса
Matrix
, поэтому невозможно написать функцию, получающую объект класса
Matrix
как аргумент (но можно написать шаблон).

void init(Matrix& a); // ошибка: пропущены тип элементов

                      // и количество размерностей

Обратите внимание на то, что библиотека

Matrix
не содержит матричных операций, например, сложение двух четырехмерных матриц или умножение двумерных матриц с одномерными. Элегантная реализация этих операций выходит за рамки этой библиотеки. Соответствующие матричные библиотеки можно надстроить над библиотекой
Matrix
(см. упр. 12). 

24.5.2. Одномерный объект класса Matrix

Что можно сделать с простейшим объектом класса

Matrix
— одномерной матрицей?

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

Matrix<int,1> a1(8); // a1 — это одномерная матрица целых чисел

Matrix<int> a(8);    // т.е. Matrix<int,1> a(8);

Таким образом, объекты

a
и
a1
имеют одинаковый тип (
Matrix<int,1>
). У каждого объекта класса
Matrix
можно запросить общее количество элементов и количество элементов в определенном измерении. У одномерного объекта класса
Matrix
эти параметры совпадают.

a.size(); // количество элементов в объекте класса Matrix

a.dim1(); // количество элементов в первом измерении

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

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
, является пустой матрицей (это позволяет избежать ошибки).

335
{"b":"847443","o":1}