2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




 
 operator [][]
Сообщение29.11.2009, 15:42 
Ну собственно я хочу сделать клас алгебраическа матрица, но с зарание неизвестным размером, но так как в с++ многомерные матрици нельязя параметоризовать по всем измерениям, то я решил сделать хранить данные в обычном массиве, и мне хотелось бы иметь удобный интерфейс к его елементам, а удобно мне будет если я смогу записать чтото типа
Код:
matrix[2][1] = 1;

Я придумал только два варианта :
1) исползовать функциональный подход( просто, легко, и некрасиво)
2) повводить промежуточные класы столпцов,и строк, написать для них приват операторы(прекрасный интерфес, но весьма громоздкий механизм)

Подскажите как это сделать попроще. Или хотябы прокоментируйте пункт 2).

 
 
 
 Re: operator [][]
Сообщение29.11.2009, 16:23 
Ну, классы и столбцов, и строк вводить не надо. Только строк. Примерно так чтоб было:
Используется синтаксис C
MatrixRow operator[] (Matrix m, unsigned i);
double& operator[] (MatrixRow m, unsigned i);

Может, кто-нибудь (не я :) ) знает ещё какой-нибудь метод, кроме описанных вами.
В классе строки будет ссылка на массив, который лежит в классе Matrix, и индекс этой самой строки. Больше ничего и не надо. Только не пойму, зачем объявлять оператор [] у строки private? Ведь к нему не будет доступа. Нужен public!

Я не очень хорошо знаю си, надеюсь, не попутал ничего.

 
 
 
 Re: operator [][]
Сообщение29.11.2009, 16:52 
Можно ещё из первого оператора возвращать простой указатель на элементы строк.

 
 
 
 Re: operator [][]
Сообщение29.11.2009, 17:11 
Можно переопределить оператор () для получения двухиндексной адресации.
С другой стороны, вы не указали, с какой целью разрабатывается класс. Вообще операция получения строки или столбца матрица является совершенно нормальной, и если можно реализовать это всё так, чтобы возвращалась ссылка на кого-то из них (столбец, строку), то логично это сделать. Ещё с другой стороны всё равно вряд ли получится очень эффективно реализовать операции над матрицами, чтобы не возвращать их по значению всюду, поэтому такая оптимизация может оказаться совершенно не нужной.

 
 
 
 Re: operator [][]
Сообщение29.11.2009, 17:33 
Можно как [R][C], так и (R, C) сделать, кстати! Чтобы на любой вкус! :D

 
 
 
 Re: operator [][]
Сообщение29.11.2009, 18:53 
arseniiv в сообщении #266368 писал(а):
Ну, классы и столбцов, и строк вводить не надо. Только строк. Примерно так чтоб было:
Используется синтаксис C
MatrixRow operator[] (Matrix m, unsigned i);
double& operator[] (MatrixRow m, unsigned i);

Может, кто-нибудь (не я :) ) знает ещё какой-нибудь метод, кроме описанных вами.
В классе строки будет ссылка на массив, который лежит в классе Matrix, и индекс этой самой строки. Больше ничего и не надо. Только не пойму, зачем объявлять оператор [] у строки private? Ведь к нему не будет доступа. Нужен public!

Я не очень хорошо знаю си, надеюсь, не попутал ничего.

Да я опечатался, я имел ввиду ввести свой приват клас строка.
Кстати наверно так и сделаю, ведь строки мне всёравно надо, клас ведь алгебраический.

 
 
 
 Re: operator [][]
Сообщение29.11.2009, 21:52 
2Nerazumovskiy
Цитата:
в с++ многомерные матрици нельязя параметоризовать по всем измерениям

Что вы имели ввиду? :) Матрицы на основе обычных указателей могут иметь любое количество измерений и любые размеры по ним. Можете реализовать библиотеку поддержки тензорного исчисления, к примеру. Или я вас неправильно понял? Я имел ввиду, что размеры-то можно менять динамически, перераспределяя память...

Цитата:
исползовать функциональный подход

Это как? Или вы говорите о круглых скобках?

Цитата:
повводить промежуточные класы столпцов,и строк

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

Хотя, понятно, что лучше иметь отдельный класс, инкапсулирующий матрицы. Это может пригодиться при оптимизации операций над матрицами специального вида, ну типа разреженных там всяких...

Если нужна многомерность матриц, то можно поэкспериментировать с "рекурсивными" типами данных, представляя матрицу в виде вектора матриц, имеющих на единицу меньшую размерность.

P.S.: Ну и конечно же не забывайте про шаблоны выражений (expression templates).
P.P.S.: В сторону Blitz++ смотрели?

 
 
 
 Re: operator [][]
Сообщение30.11.2009, 00:25 
2Circiter
Да судя по всему Blitz++ шикарная библиотека, но у меня лабораторная сформулирована так : никаких сторонних модулей, кроме стандартной библиотеки :)

Так, ну этот хитрый механиз с промежуточным класом(Row) я уже реализовал, но не всё так харашо как хотелось бы,
собственно operator[][] работает на ура, а вот при попытке прицепить к строкам арифметические операции наблюдаю очень упорное противостояние, причом настолько упорное что даже немогу понять чтоже ему не нравиться(строчку с ошибкой я нашол, а вот причину так и непонял), наверно буду использовать для получения юзабельных строк чтото вроде метода $.at()$ (именно его я имел ввиду когда говорил о функциональном подходе).

P.S.Если хтото обяснит почемуже арифметки со строками в данном случае невозможна через клас Row(или обяснит как ее таки сделать) это будет весьма познавательно. (для меня так точно)



Для тех кому интересно:
1) исходний код
2) под арифметикой строк я имею ввиду виражение:
Код:
Matrix a(/*size =*/ 3);
cin>>a;
a[0] = a[1] + a[2];

ошибка вилетает в операторе =

_______________________________
Написав пост выше я думал что у меня ничего не работает, но внезапно закоментировал две строчки и всё заработало правильно, что меня повергло в шок, ведь я даже могу обяснить почему оно не должно работать так как работает. И кстати говоря я даже нашол случай когда оно не работает, но опятьже обяснить немогу.

______
закоментировал я строчки тут:
Код:
Row& Row::operator =(const Row & a)
{
   if( this == &a) return *this;
   //delete[] m;
//   m = new Frac[a.s];
   s = a.s;
   for(int i=0;i<s;i++)
   {
      m[i] = a.m[i];
   }
   return *this;
}

и теперь по идее я несмогу дублировать данные, и скопированные обэкты будут указывать в одно и тоже место. Но при этом если я пишу
Код:
Matrix a,b;
   cout<<"Enter Matrix  3*3"<<endl;
   cin>>a;
   cout<<a;

   b[0] = a[0];
   a[0] = a[1]+ a[0];
   cout<<"a ="<<a<<endl;
   cout<<b;

а сделать этот код неработающим можно просто написав так:
Код:
Matrix a,b,c;//все матрици по умолчанию 3*3, с изначально нулевыми елементами(мне так удобней)
   cout<<"Enter Matrix  3*3"<<endl;
   cin>>a;
   cout<<a;
b =c;
   b[0] = a[0];
   a[0] = a[1]+ a[0];
   cout<<"a ="<<a<<endl;
   cout<<b;



P.P.S. собственно исходний код всего этого чудища: http://dl.dropbox.com/u/2375611/Matrix.rar

-- Вс ноя 29, 2009 23:27:27 --

arseniiv в сообщении #266400 писал(а):
Можно как [R][C], так и (R, C) сделать, кстати! Чтобы на любой вкус! :D

А можна пример как это сделать, ато я вот тут уже третье колесо к велосипеду изобретаю.

 
 
 
 Re: operator [][]
Сообщение30.11.2009, 17:01 
Вобщемто я уже розобрался, идея была в том что я просто забыл для матриц сделать оператор = :)

 
 
 
 Re: operator [][]
Сообщение30.11.2009, 19:46 
Nerazumovskiy в сообщении #266608 писал(а):
А можна пример как это сделать, ато я вот тут уже третье колесо к велосипеду изобретаю.

Ну, это я имел ввиду, что можно и метод через промежуточные строчки, и перегруженный () использовать. Кому не понравятся строчки, пусть использует () :D
Кстати, я думал, т.к. чтроки привязаны к матрице, их не надо никуда удалять, а вы сначала удаляли и пересоздавали. Матрица-то испортится от таких манипуляций! У вас что хранится в строке? Лучше бы она хранила две вещи: указатель на "свой" дин. массив из матрицы, которая её создала и индекс. Тогда можно вот как поправить:
код: [ скачать ] [ спрятать ]
Используется синтаксис C
// поле linked - логическое: присоединена ли строка к матрице (или же она "плавает". Например, такая нужна для суммы-разности строк)
// поле row - указатель на строку из матрицы, если создана одним конструктором (там параметрами будут индекс и "родительская" матрица) ИЛИ динамически выделенная в другом конструкторе строка (там параметр - длина строки). Соответственно конструктору поставится свойство linked.
// поле len должно хранить длину строки
// в деструкторе, если !linked, строка удаляется
// у вас тут какая-то игра со звёздочками была, хотя тут же ясно указан тип &, так что ничего не надо
Row &Row::operator=(const Row &a)
{
  if (row == a.row) return this;
  if (linked && len != a.len) {
    // тут генерьте ошибку. Не пристало матрицам подстраиваться под чужие строчки ; )
  }
  len = a.len;
  for (int i = 0; i < len; i++) row[i] = a.row[i];
  return this;
}
// пример операции +
Row &Row::operator+(const Row &a, const Row &b)
{
  unsigned len;
  if ((len = a.len) != b.len) {
    // опять же, не пристало
  }
  Row *r = new Row(len); // второй конструктор, плавучая строка
  for (int i = 0; i < len; i++) r.row[i] = a.row[i] + b.row[i];
  return r;  
}
 
Надеюсь, снова ничего не напутал.

-- Пн ноя 30, 2009 22:50:52 --

(Только, конечно, operator+= надо реализовывать не через operator+. А то будет создаваться временная строка и уничтожаться. Он будет совершенно похож на operator= за исключением строки с присваиванием, которое будет заменено на +=.)

 
 
 
 Re: operator [][]
Сообщение30.11.2009, 21:21 
Кстати, в operator+ параметры и результат -ссылки не нужны, надо их сделать простыми. (Можно и так оставить, просто "лишний груз" будет.) :)

 
 
 
 Re: operator [][]
Сообщение01.12.2009, 12:09 
Они не просто не нужны, но и категорически противопоказаны. Во-первых, они довольно неудобны с точки зрения интерфейса (например, если будет оператор == на рядах, то мы не сможем написать if (a == b + c)), результатом работы оператора является исключительно lhs-value. Во-вторых, и главное, у вас с таким подходом - возвращение ссылки на созданный в куче объект - произойдёт утечка памяти: если у вас были объекты Row row1, row2, row3, то после вызова row1 = row2 + row3 переменная row1 будет ссылаться на новый объект, а ссылка на старый потеряется, и никто не займётся его удалением. Отслеживать это вручную - непосильная задача.
Способы этого избежать есть разные. Простейший из них - всё возвращать в программе по значению. Многие компиляторы имеют return value optimization, поэтому можно приступить к оптимизированию этого только после того, как вы произвели замеры и выяснили, что текущей скорости вам недостаточно, а медленным элементом является возвращение значений.
Остальные способы гораздо более трудоемкие и сложные в реализации, они связаны с другим проектированием системы классов - введением дескрипторов объектов или работой с автоматическими указателями от объектов. Наверное, есть и другие способы, но я их не знаю.

 
 
 [ Сообщений: 12 ] 


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group