Форум программистов, компьютерный форум CyberForum.ru

Как правильней делать матрицу-объект? - C++

Восстановить пароль Регистрация
 
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
09.10.2012, 20:20     Как правильней делать матрицу-объект? #1
Сделать динамический одномерный массив - не проблема, проблема в том, что матрица должна быть строго прямоугольной, а состоять из массивов. А если написать
C++
1
m[2]=v;
, где v - одномерный массив, а m - матрица с числом столбцов, отличным от числа элементов v? Или
C++
1
m[3].resize(10);
? Вот это и вызывает вопросы.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.10.2012, 20:20     Как правильней делать матрицу-объект?
Посмотрите здесь:

Как умножить матрицу на матрицу C++
Как умножить матрицу на матрицу? C++
Списки. Как правильней организовать? C++
интерфейс, в методе которого создается объект типа IDictionary и возвращается ссылка на этот объект C++
Что значит константный указатель на объект, указатель на константный объект, и как это можно использовать? C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
09.10.2012, 20:25     Как правильней делать матрицу-объект? #2
ну как обычно. написать класс, в котором инкапсулировать все особенности, туда же засунуть все нужные проверки и кидать\возвращать ошибки если клиентский код эти методы начинает вызвать неправильно. написать удобные для клиентского кода функции и радоваться красивому и простому коду.

И кстати вопрос как-то непонятно сформулирован. Не хватает информации.
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
09.10.2012, 20:37  [ТС]     Как правильней делать матрицу-объект? #3
Надо реализовать класс строго прямоугольного динамического массива и перегрузить операции сложения, вычитания и умножения, написать методы, возвращающие: определитель, обратную матрицу, транспонированную матрицу. Ресайз строки должен быть закрыт, но элемент адресоваться в через два индеса, то есть, например,
C++
1
x=m[2][6];
. При этом у матрица в целом ресайз должен быть открыт, например,
C++
1
m.resize(10, 20);
должен менять и количество строк на 10 и длины всех строк на 20. Адресация в один индекс, например,
C++
1
r=m[8];
должна возвращать строку-объект. Надо поддерживать присваивание сразу всей строки, например,
C++
1
m[8]=r;
, но только при равенстве размеров строки и присваиваемого ей массива. При этом присваивание целиком всей матрицы вообще не должно зависеть от совпадения размеров. Как это делается? Я почему то не могу сочинить даже декларацию.
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
09.10.2012, 21:39     Как правильней делать матрицу-объект? #4
Вот если в кратце то так:
Завести класс строк, класс ссылок на строк и класс матрицы.
матрица будет возвращать ссылочные строки, которые не позволяют изменять реальные строки, на которые они ссылаются. этим самым будет невозможен такой код: m[i].resize();
При этом снабдить всех правильными конструкторами и операторами =, чтобы были проверки и работало согласно требованиям.
Вот в быстренькое решение на коленке со своими проблемами . неконстантность оператора [], нужно следить за протуханием ссылочных строк и прочее. но для точки отсчета должно пригодится:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <vector>
 
template <typename T>
class Row;
 
template <typename T>
class RowRef;
 
 
template <typename T>
class Row
{
public:
  Row()
  {
  }
 
  Row(const RowRef<T>& rowRef);
  Row& operator = (const RowRef<T>& rowRef);
 
  const T& operator [] (unsigned index) const
  {
    return m_data[index];
  }
 
  T& operator [] (unsigned index) 
  {
    return m_data[index];
  }
 
  unsigned getSize() const
  {
    return static_cast<unsigned>(m_data.size());
  }
 
  void resize(unsigned size)
  {
    // тут нужна более умная реализация, позволяющая уменьшать размеры
    // и сохраняющая или не сохраняющая уже имеющиеся данные.
    m_data.resize(size);
  }
 
private:
  std::vector<T> m_data;
};
 
 
template <typename T>
class RowRef
{
public:
  explicit RowRef(Row<T>& row)
    : m_row(&row)
  {
  }
 
  RowRef& operator = (const Row<T>& row)
  {
    if (m_row->getSize() == row.getSize())
    {
      *m_row = row;
    }
    return *this;
  }
 
  const T& operator [] (unsigned index) const
  {
    return (*m_row)[index];
  }
 
  T& operator [] (unsigned index) 
  {
    return (*m_row)[index];
  }
 
  unsigned getSize() const
  {
    return m_row->getSize();
  }
 
private:
  Row<T>* m_row;
};
 
 
template <typename T>
Row<T>::Row(const RowRef<T>& rowRef)
  : m_data(&rowRef[0], &rowRef[0] + rowRef.getSize())
{
}
 
template <typename T>
Row<T>& Row<T>::operator = (const RowRef<T>& rowRef)
{
  m_data.assign(&rowRef[0], &rowRef[0] + rowRef.getSize());
  return this;
}
 
 
template <typename T>
class Matrix
{
public:
  // Проблема. С помощью возвращенной ссылки можно поменять строку. Нужно возвращать что-то, через что это сделать нельзя.
  RowRef<T> operator [] (unsigned index) const
  {
    return RowRef(m_rows[index]);
  }
 
  RowRef<T> operator [] (unsigned index) 
  {
    return RowRef<T>(m_rows[index]);
  }
 
  void resize(unsigned rows, unsigned columns)
  {
    // тут нужна более умная реализация, позволяющая уменьшать размеры
    // и сохраняющая или не сохраняющая уже имеющиеся данные.
    m_rows.resize(rows);
    for (std::vector< Row<T> >::iterator it = m_rows.begin(), end = m_rows.end(); it != end; ++it)
    {
      it->resize(columns);
    }
  }
 
  unsigned getRows() const
  {
    return m_rows.size();
  }
 
  unsigned getColumns() const
  {
    return m_rows.empty() ? 0 : m_rows[0].getSize();
  }
 
private:
  std::vector< Row<T> > m_rows;
};
 
 
 
int main()
{
  Matrix<int> m;
  m.resize(5, 5);
  m[1][1] = 10;
//  m[1].resize(10); // это не компилится. потому что возвращается RowRef у которого нет метода ресайза
  Row<int> r = m[1]; // ok. у Row есть конструктор, который принимает RowRef и копирует в себя все данные из ссылочной строки.
  m[1] = r; // RowRef имеет оператор =, который копирует из r данные если размеры строк совпадают.
  r.resize(10); // это можно ресайзить, потому что это копия строки из матрицы. все изменения с этой строкой не влияют на размеры и значения исходной матрицы
  m[1] = r; // не пройдет. разные размеры у матричной строки и у этой копии.
 
  return 0;
}
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
10.10.2012, 10:58  [ТС]     Как правильней делать матрицу-объект? #5
Идея в подставном классе, экземпляры которого возвращаются по оператору индексации?
Yandex
Объявления
10.10.2012, 10:58     Как правильней делать матрицу-объект?
Ответ Создать тему
Опции темы

Текущее время: 03:38. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru