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

Абстрактный шаблонный класс - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 35, средняя оценка - 4.83
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
26.09.2010, 03:22     Абстрактный шаблонный класс #1
Вообщем какое дело. У меня есть класс матрица, который сделан с использованием шаблонов и STL. В нем перегружены операторы ввода/вывода в поток(то, что их не врубить в динамический полиморфизм я уже понял).

Первый класс:

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
    //Класс матрицы
    template<class T>
    class Matr
    {
    public:
       Matr();
       Matr(size_t n, size_t m);
       Matr(const Matr&);
       virtual ~Matr();
       void SetSize(size_t n, size_t m);
       const size_t GetRow() const {return Matrix.size();}
       const size_t GetCol() const {return Matrix[0].size();}
       template<class T2>
       friend std::ostream& operator <<(std::ostream& os, const Matr<T2>& Ob);
       template<class T2>
       friend std::istream& operator >>(std::istream& is, Matr<T2>& Ob);
       Matr<T>& operator =(const Matr&);
       Matr<T> operator +=(const Matr&);
       Matr<T> operator +(const Matr&);
       Matr<T> operator *=(const Matr&);
       Matr<T> operator *(const Matr&);
       void random_fill();
    protected:
       std::vector<std::vector<T> > Matrix;
    };
Определение функций писать не буду, пока это не нужно. Вряд ли 200 строк чем-то помогут. Виртуальными эту перегрузку не сделать. И если я пишу второй код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
template<class T>
class ConsoleMatr:public Matr<T>
{
public:
   ConsoleMatr():Matr() {}
   ConsoleMatr(size_t n, size_t m):Matr(n, m) {}
   ConsoleMatr(const Matr& Ob):Matr(Ob) {}
   template<class T2>
   friend std::ostream& operator <<(std::ostream& os, const ConsoleMatr<T2>& Ob);
   template<class T2>
   friend std::istream& operator >>(std::istream& is, ConsoleMatr<T2>& Ob);
};
И комментирую эти методы в исходном классе, то как реализовать динамический полиморфизм?

Пробую так.
C++
1
2
3
4
5
6
7
8
typedef std::auto_ptr<Matr<int> > MatrSP;
 
int main()
{
   MatrSP Ob(new ConsoleMatr);
   std::cin>>Ob;
   //
}
Пишет ошибку. Впринципе это понятно. Тогда вопрос, как реализовать??

А так же есть вариант оставить оба варианта. Но будут вызываться операторы ввода/вывода из класса Matr.

И следующий вопрос. Добавляю в первый класс две чисто виртуальные функции. Класс принимает вид:

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
    //Класс матрицы
    template<class T>
    class Matr
    {
    public:
       Matr();
       Matr(size_t n, size_t m);
       Matr(const Matr&);
       virtual ~Matr();
       void SetSize(size_t n, size_t m);
       const size_t GetRow() const {return Matrix.size();}
       const size_t GetCol() const {return Matrix[0].size();}
       template<class T2>
       friend std::ostream& operator <<(std::ostream& os, const Matr<T2>& Ob);
       template<class T2>
       friend std::istream& operator >>(std::istream& is, Matr<T2>& Ob);
       Matr<T>& operator =(const Matr&);
       Matr<T> operator +=(const Matr&);
       Matr<T> operator +(const Matr&);
       Matr<T> operator *=(const Matr&);
       Matr<T> operator *(const Matr&);
       void random_fill();
           virtual void input()=0;
           virtual void output()=0;
    protected:
       std::vector<std::vector<T> > Matrix;
    };
А второй.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template<class T>
class ConsoleMatr:public Matr<T>
{
public:
   ConsoleMatr():Matr() {}
   ConsoleMatr(size_t n, size_t m):Matr(n, m) {}
   ConsoleMatr(const Matr& Ob):Matr(Ob) {}
   template<class T2>
   friend std::ostream& operator <<(std::ostream& os, const ConsoleMatr<T2>& Ob);
   template<class T2>
   friend std::istream& operator >>(std::istream& is, ConsoleMatr<T2>& Ob);
   void input();
   void output();
};
Вот так впринципе вполне неплохо идет полиморфизм. Но есть одно НО...

Ошибка происходит в этой функции.

C++
1
2
3
4
5
6
7
    template<class T>
    Matr<T> Matr<T>::operator *(const Matr<T> &Ob)
    {
          Matr<T> Obj(*this);   
          Obj*=Ob;
          return Obj;
    }
Нельзя инстанцинировать абстрактный класс... Что тоже понятно... Но непонятно, как тогда это реализовать. Или же забить на это и оставить как есть?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
26.09.2010, 03:22     Абстрактный шаблонный класс
Посмотрите здесь:

C++ Шаблонный класс
Переделать класс в шаблонный класс C++
C++ Шаблонный класс
Шаблонный класс C++
C++ Шаблонный класс
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
26.09.2010, 19:29  [ТС]     Абстрактный шаблонный класс #21
alexzak, Понято. Буду завтра днем думать как быть. Спасибо за информацию.

Добавлено через 9 часов 14 минут
3начит в этой 3адаче не стоит исполь3овать указатели? Чере3 объекты конкр. класса лучше? Да и вообще есть ли смысл разделять, если есть перегру3ка операторов ввода/вывода и резон есть-ли делать все же через абстрактный класс?

Не по теме:

Если не понятно что пишу извините. Спросони.



Добавлено через 2 часа 7 минут
Это возможно как-то сделать без переписывания всего? А то что-то совсем не хочется переписывать всю программу с нуля практически

Добавлено через 2 часа 20 минут
П.С. насколько я понимаю самый простой метод это пользоваться функциями, а не перегрузкой операторов, в таком случае проблем не будет... Но все же это как-то нехорошо...
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
alexzak
84 / 57 / 1
Регистрация: 07.08.2010
Сообщений: 185
26.09.2010, 21:23     Абстрактный шаблонный класс #22
Цитата Сообщение от Lavroff Посмотреть сообщение
3начит в этой 3адаче не стоит исполь3овать указатели? Чере3 объекты конкр. класса лучше? Да и вообще есть ли смысл разделять, если есть перегру3ка операторов ввода/вывода и резон есть-ли делать все же через абстрактный класс?
Правильно. Вообще, идея о том, что в Matr можно добавить функциональность ввода/вывода, унаследовав от него ConsoleMatr, плохая. Наследование для добавления функциональности - это пример неправильного его использования. В данном случае Matr не был изначально сделан как полиморфный класс. Поэтому когда пытаешься от него унаследоваться, возникают проблемы. Лучше добавить ввод/вывод через свободные операторы << и >>. В последнее время такой метод (свободные операторы и функции) стал очень популярен в С++, потому что он избавлен от проблем, возникающих при наследовании.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
26.09.2010, 21:56  [ТС]     Абстрактный шаблонный класс #23
alexzak, Свободные операторы то есть? Пример можно? Операторы не в классе?
alexzak
84 / 57 / 1
Регистрация: 07.08.2010
Сообщений: 185
26.09.2010, 21:59     Абстрактный шаблонный класс #24
Да, те, для которых не надо изменять класс, например:
C++
1
2
ostream & operator<<(ostream & out, Matr const & m);
Matr operator+(Matr const & lhs, Matr const & rhs);
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
27.09.2010, 07:41  [ТС]     Абстрактный шаблонный класс #25
alexzak, Понято. Я тут пытаюсь что-то сделать. Почти доделал. Если получится - скину код.

Добавлено через 23 минуты
Кхм. Не помогают танцы с бубном. Не понимаю почему.

Код
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#ifndef _MATRIX_H_
#define _MATRIX_H_
 
namespace MatrSpace
{
    template<class T>
    class AbstractMatr
    {
    public:
        AbstractMatr() {}
        AbstractMatr(size_t n, size_t m);
        AbstractMatr(const AbstractMatr&);
        virtual ~AbstractMatr() {}
        void SetSize(size_t n, size_t m);
        inline const size_t GetRow() const {return Matrix.size();}
        inline const size_t GetCol() const {return Matrix[0].size();}
        virtual void input(std::ostream&)=0;
        virtual void output(std::istream&)=0;
    protected:
        std::vector<std::vector<T> > Matrix;
    };
 
    template<class T>
    class MathMatr:public AbstractMatr<T>
    {
    public:
        MathMatr():AbstractMatr() {}
        MathMatr(size_t n, size_t m):AbstractMatr<T>(n, m) {}
        MathMatr(const AbstractMatr<T>& Ob):AbstractMatr<T>(Ob) {}
        virtual ~MathMatr() {}
        MathMatr<T>& operator =(const MathMatr&);
        MathMatr<T> operator +=(const MathMatr&);
        MathMatr<T> operator +(const MathMatr&);
        MathMatr<T> operator *=(const MathMatr&);
        MathMatr<T> operator *(const MathMatr&);
        virtual void input(std::istream&) {}
        virtual void output(std::ostream&) {}
        template<class T2>
        friend std::ostream& operator <<(std::ostream&, const MathMatr<T2>& Ob);
        template<class T2>
        friend std::istream& operator >>(std::istream&, MathMatr<T2>& Ob);
        void random_fill();
    };
 
    template<class T>
    class ConsoleMatr:public MathMatr<T>
    {
    public:
        ConsoleMatr():MathMatr() {}
        ConsoleMatr(size_t n, size_t m):MathMatr(n, m) {}
        ConsoleMatr(const AbstractMatr<T>& Ob):MathMatr(Ob) {}
        virtual ~ConsoleMatr() {}
        void input(std::istream&);
        void output(std::ostream&);
    };
 
    template<class T>
    AbstractMatr<T>::AbstractMatr(size_t n, size_t m)
    {
        Matrix.resize(n);
        for(int i=0; i!=GetRow(); ++i)
        {
            Matrix[i].resize(m);
        }
    }
 
    template<class T>
    AbstractMatr<T>::AbstractMatr(const AbstractMatr<T> &Ob)
    {
        SetSize(Ob.GetRow, Ob.GetCol());
        for(int i=0; i!=Ob.GetRow(); ++i)
        {
            std::copy(Ob.Matrix[i].begin(), Ob.Matrix[i].end(), Matrix.begin());
        }
    }
 
    template<class T>
    void AbstractMatr<T>::SetSize(size_t n, size_t m)
    {
        if(GetRow!=0&&GetCol()!=0)
            Matrix.clear();
        Matrix.resize(n);
        for(int i=0; i!=GetRow(); ++i)
        {
            Matrix[i].resize(m);
        }
    }
 
    template<class T>
    MathMatr<T>& MathMatr<T>::operator =(const MathMatr<T>& Ob)
    {
        if(this==&Ob)
            return *this;
        SetSize(Ob.GetRow(), Ob.GetCol());
        for(int i=0; i!=GetRow(); ++i)
        {
            std::copy(Ob.Matrix[i].begin(), Ob.Matrix[i].end(), Matrix[i].begin());
        }
        return *this;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator +=(const MathMatr<T>& Ob)
    {
        if(GetRow()!=Ob.GetRow()&&GetCol()!=Ob.GetCol())
           throw std::string("Size of two matrix for sum must be equal!");
        for(int i=0; i!=Ob.GetRow(); ++i)
        {
           for(int j=0; j!=Ob.GetCol(); ++j)
           {
              Matrix[i][j]+=Ob.Matrix[i][j];
           }
        }
        return *this;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator +(const MathMatr<T>& Ob)
    {
        MathMatr<T> Temp(*this);
        Temp+=Ob;
        return Temp;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator *=(const MathMatr<T>& Ob)
    {
        if(GetCol()!=Ob.GetRow())
            throw std::string("Num of 1-st matrix cols must be equal to num of 2-nd matrix rows");
        MathMatr Temp(GetRow(), Ob.GetCol());
        for(int i=0; i!=Temp.GetRow(); ++i)
        {
           for(int j=0; j!=Temp.GetCol(); ++j)
           {
              Temp.Matrix[i][j]=0;
              for(int k=0; k!=GetCol(); ++k)
              {
                 Temp.Matrix[i][j]+=Matrix[i][k]*Ob.Matrix[k][j];
              }
            }
        }
        *this=Temp;
        return *this;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator *(const MathMatr<T>& Ob)
    {
        MathMatr<T> Temp(*this);
        Temp+=Ob;
        return Temp;
    }
 
    template<class T>
    void MathMatr<T>::random_fill()
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
             Matrix[i][j]=1+rand()%50;
          }
       }
    }
 
    template<class T>
    std::ostream& operator <<(std::ostream& os, const MathMatr<T>& Ob)
    {
       Ob.output(os);
       return os;
    }
 
    template<class T>
    std::istream& operator >>(std::istream& is, MathMatr<T>& Ob)
    {
       Ob.input(is);
       return is;
    }
 
    template<class T>
    void ConsoleMatr<T>::input(std::istream& is)
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
              std::cout<<"Enter Matrix ["<<i+1<<"]["<<j+1<<"]: ";
              is>>Matrix[i][j];
          }
       }
    }
 
    template<class T>
    void ConsoleMatr<T>::output(std::ostream& os)
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
              os<<std::setw(5)<<Matrix[i][j]<<' ';
          }
          std::cout<<std::endl;
       }
    }
}


Все бы ничего... Но при попытке вызова:
C++
1
   MathMatr<int> Ob1;
или
C++
1
   std::auto_ptr<AbstractMatr<int> > Ob(new ConsoleMatr<int>);
Пишется ошибка:
Error 1 error C2259: 'MatrSpace::ConsoleMatr<T>' : cannot instantiate abstract class c:\программирование\страуструп\глава 4\matirx\matirx\matrix.cpp 16

Всю голову уже переломал... Вроде бы все что нужно реализовано.

Добавлено через 34 минуты
Проблему нашел. Собственно, Проблема была в двух абстрактных функциях... Сделав класс конкретным стало лучше... Но ненамного...

Добавлено через 8 часов 39 минут
Все исправил... Однако только если первый класс не является абстрактным. В чем может быть проблема? Ведь насколько я понимаю наследование от абстрактного класса должно идти нормально...

Код:

...
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
#ifndef _MATRIX_H_
#define _MATRIX_H_
 
namespace MatrSpace
{
    template<class T>
    class AbstractMatr
    {
    public:
        AbstractMatr() {}
        AbstractMatr(size_t n, size_t m);
        AbstractMatr(const AbstractMatr&);
        virtual ~AbstractMatr() {}
        void SetSize(size_t n, size_t m);
        inline const size_t GetRow() const {return Matrix.size();}
        inline const size_t GetCol() const {return Matrix[0].size();}
        virtual void input(std::ostream&)=0;
        virtual void output(std::istream&)=0;
    protected:
        std::vector<std::vector<T> > Matrix;
    };
 
    template<class T>
    class MathMatr:public AbstractMatr<T>
    {
    public:
        //MathMatr(AbstractMatr<T>*P):Pointer(p) {}
        MathMatr():AbstractMatr() {}
        MathMatr(size_t n, size_t m):AbstractMatr<T>(n, m) {}
        MathMatr(const AbstractMatr<T>& Ob):AbstractMatr<T>(Ob) {}
        virtual ~MathMatr() {}
        MathMatr<T>& operator =(const MathMatr&);
        MathMatr<T> operator +=(const MathMatr&);
        MathMatr<T> operator +(const MathMatr&);
        MathMatr<T> operator *=(const MathMatr&);
        MathMatr<T> operator *(const MathMatr&);
        virtual void input(std::istream&) {}
        virtual void output(std::ostream&) {}
        template<class T2>
        friend std::ostream& operator <<(std::ostream&, MathMatr<T2>& Ob);
        template<class T2>
        friend std::istream& operator >>(std::istream&, MathMatr<T2>& Ob);
        void random_fill();
    protected:
        //AbstractMatr<T>*Pointer;
    };
 
    template<class T>
    class ConsoleMatr:public MathMatr<T>
    {
    public:
        ConsoleMatr():MathMatr() {}
        ConsoleMatr(size_t n, size_t m):MathMatr(n, m) {}
        ConsoleMatr(const AbstractMatr<T>& Ob):MathMatr<T>(Ob) {}
        virtual ~ConsoleMatr() {}
        ConsoleMatr<T>& operator =(const ConsoleMatr&);
        ConsoleMatr<T> operator +=(const ConsoleMatr&);
        ConsoleMatr<T> operator +(const ConsoleMatr&);
        ConsoleMatr<T> operator *=(const ConsoleMatr&);
        ConsoleMatr<T> operator *(const ConsoleMatr&);
        virtual void input(std::istream&);
        virtual void output(std::ostream&);
    };
 
    template<class T>
    AbstractMatr<T>::AbstractMatr(size_t n, size_t m)
    {
        Matrix.resize(n);
        for(int i=0; i!=GetRow(); ++i)
        {
            Matrix[i].resize(m);
        }
    }
 
    template<class T>
    AbstractMatr<T>::AbstractMatr(const AbstractMatr<T> &Ob)
    {
        SetSize(Ob.GetRow(), Ob.GetCol());
        for(int i=0; i!=Ob.GetRow(); ++i)
        {
            std::copy(Ob.Matrix[i].begin(), Ob.Matrix[i].end(), Matrix[i].begin());
        }
    }
 
    template<class T>
    void AbstractMatr<T>::SetSize(size_t n, size_t m)
    {
        if(GetRow()!=0&&GetCol()!=0)
            Matrix.clear();
        Matrix.resize(n);
        for(int i=0; i!=GetRow(); ++i)
        {
            Matrix[i].resize(m);
        }
    }
 
    template<class T>
    MathMatr<T>& MathMatr<T>::operator =(const MathMatr<T>& Ob)
    {
        if(this==&Ob)
            return *this;
        SetSize(Ob.GetRow(), Ob.GetCol());
        for(int i=0; i!=GetRow(); ++i)
        {
            std::copy(Ob.Matrix[i].begin(), Ob.Matrix[i].end(), Matrix[i].begin());
        }
        return *this;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator +=(const MathMatr<T>& Ob)
    {
        if(GetRow()!=Ob.GetRow()&&GetCol()!=Ob.GetCol())
           throw std::string("Size of two matrix for sum must be equal!");
        for(int i=0; i!=Ob.GetRow(); ++i)
        {
           for(int j=0; j!=Ob.GetCol(); ++j)
           {
              Matrix[i][j]+=Ob.Matrix[i][j];
           }
        }
        return *this;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator +(const MathMatr<T>& Ob)
    {
        MathMatr<T> Temp(*this);
        Temp+=Ob;
        return Temp;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator *=(const MathMatr<T>& Ob)
    {
    *   if(GetCol()!=Ob.GetRow())
            throw std::string("Num of 1-st matrix cols must be equal to num of 2-nd matrix rows");
        MathMatr Temp(GetRow(), Ob.GetCol());
        for(int i=0; i!=Temp.GetRow(); ++i)
        {
           for(int j=0; j!=Temp.GetCol(); ++j)
           {
              Temp.Matrix[i][j]=0;
              for(int k=0; k!=GetCol(); ++k)
              {
                 Temp.Matrix[i][j]+=Matrix[i][k]*Ob.Matrix[k][j];
              }
            }
        }
        *this=Temp;
        return *this;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator *(const MathMatr<T>& Ob)
    {
        MathMatr<T> Temp(*this);
        Temp*=Ob;
        return Temp;
    }
 
    template<class T>
    void MathMatr<T>::random_fill()
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
             Matrix[i][j]=1+rand()%50;
          }
       }
    }
 
    template<class T>
    std::ostream& operator <<(std::ostream& os, MathMatr<T>& Ob)
    {
       Ob.output(os);
       return os;
    }
 
    template<class T>
    std::istream& operator >>(std::istream& is, MathMatr<T>& Ob)
    {
       Ob.input(is);
       return is;
    }
 
    template<class T>
    void ConsoleMatr<T>::input(std::istream& is)
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
              std::cout<<"Enter Matrix ["<<i+1<<"]["<<j+1<<"]: ";
              is>>Matrix[i][j];
          }
       }
    }
 
    template<class T>
    void ConsoleMatr<T>::output(std::ostream& os)
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
              os<<std::setw(5)<<Matrix[i][j]<<' ';
          }
          std::cout<<std::endl;
       }
    }
 
    template<class T>
    ConsoleMatr<T>& ConsoleMatr<T>::operator =(const ConsoleMatr<T>& Ob)
    {
        if(this==&Ob)
            return *this;
        SetSize(Ob.GetRow(), Ob.GetCol());
        for(int i=0; i!=GetRow(); ++i)
        {
            std::copy(Ob.Matrix[i].begin(), Ob.Matrix[i].end(), Matrix[i].begin());
        }
        return *this;
    }
 
    template<class T>
    ConsoleMatr<T> ConsoleMatr<T>::operator +=(const ConsoleMatr<T>& Ob)
    {
        if(GetRow()!=Ob.GetRow()&&GetCol()!=Ob.GetCol())
           throw std::string("Size of two matrix for sum must be equal!");
        for(int i=0; i!=Ob.GetRow(); ++i)
        {
           for(int j=0; j!=Ob.GetCol(); ++j)
           {
              Matrix[i][j]+=Ob.Matrix[i][j];
           }
        }
        return *this;
    }
 
    template<class T>
    ConsoleMatr<T> ConsoleMatr<T>::operator +(const ConsoleMatr<T>& Ob)
    {
        ConsoleMatr<T> Temp(*this);
        Temp+=Ob;
        return Temp;
    }
 
    template<class T>
    ConsoleMatr<T> ConsoleMatr<T>::operator *=(const ConsoleMatr<T>& Ob)
    {
        if(GetCol()!=Ob.GetRow())
            throw std::string("Num of 1-st matrix cols must be equal to num of 2-nd matrix rows");
        ConsoleMatr Temp(GetRow(), Ob.GetCol());
        for(int i=0; i!=Temp.GetRow(); ++i)
        {
           for(int j=0; j!=Temp.GetCol(); ++j)
           {
              Temp.Matrix[i][j]=0;
              for(int k=0; k!=GetCol(); ++k)
              {
                 Temp.Matrix[i][j]+=Matrix[i][k]*Ob.Matrix[k][j];
              }
            }
        }
        *this=Temp;
        return *this;
    }
 
    template<class T>
    ConsoleMatr<T> ConsoleMatr<T>::operator *(const ConsoleMatr<T>& Ob)
    {
        ConsoleMatr<T> Temp(*this);
        Temp*=Ob;
        return Temp;
    }
}
#endif
Mr.X
Эксперт С++
 Аватар для Mr.X
2803 / 1579 / 247
Регистрация: 03.05.2010
Сообщений: 3,670
27.09.2010, 12:55     Абстрактный шаблонный класс #26
А так не проще будет:
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
///////////////////////////////////////////////////////////////////////////////////////
#include <iostream>
///////////////////////////////////////////////////////////////////////////////////////
template<class T>
class T_matr
{
    T t_;//Для примера.
public:
    T_matr() : t_()
    {}
    //---------------------------------------------------------------------------------
    T get()
    {
        return t_;
    }
    //---------------------------------------------------------------------------------
    void set(T t)
    {
        t_ = t;
    }
};
///////////////////////////////////////////////////////////////////////////////////////
template<class T>
class T_matr_io
{
protected:
    T_matr<T>  matr;
 
public:
    virtual ~T_matr_io(){}
    virtual void  input()   = 0;
    virtual void  output()  = 0;
    //---------------------------------------------------------------------------------
    void  print_typename()
    {
        std::cout << typeid(T).name();
    }
};
///////////////////////////////////////////////////////////////////////////////////////
template<class T>
class T_matr_io_console : public T_matr_io<T>
{
public:
    void  input()
    {
        std::cout << "Ввод матрицы с элементами типа ";
        print_typename();
        std::cout << " с консоли ->   ";
        T t;
        std::cin >> t;
        matr.set(t);
    }
    //---------------------------------------------------------------------------------
    void  output()
    {
        std::cout << "Вывод матрицы с элементами типа ";
        print_typename();
        std::cout << " на консоль -> "                  
                  << matr.get()
                  << "."
                  << std::endl;    
    }
};
///////////////////////////////////////////////////////////////////////////////////////
template<class T>
class T_matr_io_cosmos : public T_matr_io<T>
{
public:
    void  input()
    {
        std::cout << "Ввод матрицы с элементами типа ";
        print_typename();
        std::cout << " из космоса."
                  << std::endl;    
    }
    //---------------------------------------------------------------------------------
    void  output()
    {        
        std::cout << "Вывод матрицы с элементами типа ";
        print_typename();
        std::cout << " в космос."
                  << std::endl;    
    }
};
///////////////////////////////////////////////////////////////////////////////////////
int main()
{
    std::locale::global(std::locale(""));
 
    T_matr_io<int>*  p_matr_io_console_int  = new T_matr_io_console<int>;
    T_matr_io<int>*  p_matr_io_cosmos_int   = new T_matr_io_cosmos<int>;
 
    p_matr_io_console_int->input();
    p_matr_io_console_int->output();
 
    p_matr_io_cosmos_int->input();
    p_matr_io_cosmos_int->output();
   
 
    T_matr_io<char>*  p_matr_io_console_char  = new T_matr_io_console<char>;
    T_matr_io<char>*  p_matr_io_cosmos_char   = new T_matr_io_cosmos<char>;
 
    p_matr_io_console_char->input();
    p_matr_io_console_char->output();
 
    p_matr_io_cosmos_char->input();
    p_matr_io_cosmos_char->output();
}
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
28.09.2010, 04:19  [ТС]     Абстрактный шаблонный класс #27
Mr.X, Красиво. Но придется опять перетрахивать класс...

Добавлено через 5 часов 51 минуту
Дико запутался... Вообще не знаю что делать... Пытался сделать с элементом класса - запутался в собственном коде... Что посоветуете?

Добавлено через 26 минут
Чудо. Оно заработало. А проблема была всего-лишь в одном маленьком недочете. Работает оно примерно вот так. Нормальный код?
И вопрос. Стоит ли делать методы в ConsoleMatr виртуальными или же нет?
Matrix.h
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#ifndef _MATRIX_H_
#define _MATRIX_H_
 
namespace MatrSpace
{
    template<class T>
    class AbstractMatr
    {
    public:
        AbstractMatr() {}
        AbstractMatr(size_t n, size_t m);
        AbstractMatr(const AbstractMatr&);
        virtual ~AbstractMatr() {}
        void SetSize(size_t n, size_t m);
        inline const size_t GetRow() const {return Matrix.size();}
        inline const size_t GetCol() const {return Matrix[0].size();}
    protected:
        std::vector<std::vector<T> > Matrix;
    };
 
    template<class T>
    class MathMatr:public AbstractMatr<T>
    {
    public:
        MathMatr():AbstractMatr() {}
        MathMatr(size_t n, size_t m):AbstractMatr<T>(n, m) {}
        MathMatr(const AbstractMatr<T>& Ob):AbstractMatr<T>(Ob) {}
        virtual ~MathMatr() {}
        MathMatr<T>& operator =(const MathMatr&);
        MathMatr<T> operator +=(const MathMatr&);
        MathMatr<T> operator +(const MathMatr&);
        MathMatr<T> operator *=(const MathMatr&);
        MathMatr<T> operator *(const MathMatr&);
        virtual void input(std::istream&) {}
        virtual void output(std::ostream&) {}
        template<class T2>
        friend std::ostream& operator <<(std::ostream&, MathMatr<T2>& Ob);
        template<class T2>
        friend std::istream& operator >>(std::istream&, MathMatr<T2>& Ob);
        void random_fill();
    };
 
    template<class T>
    class IOMatr:public MathMatr<T>
    {
    public:
        IOMatr():MathMatr<T>() {}
        IOMatr(size_t n, size_t m):MathMatr(n, m) {}
        IOMatr(const AbstractMatr<T>& Ob):MathMatr(Ob) {}
        virtual ~IOMatr() {}
        virtual void input(std::istream&)=0;
        virtual void output(std::ostream&)=0;
    };
 
    template<class T>
    class ConsoleMatr:public IOMatr<T>
    {
    public:
        ConsoleMatr():IOMatr<T>() {}
        ConsoleMatr(size_t n, size_t m):IOMatr(n, m) {}
        ConsoleMatr(const AbstractMatr<T>& Ob):IOMatr(Ob) {}
        virtual ~ConsoleMatr() {}
        ConsoleMatr<T>& operator =(const ConsoleMatr&);
        ConsoleMatr<T> operator +=(const ConsoleMatr&);
        ConsoleMatr<T> operator +(const ConsoleMatr&);
        ConsoleMatr<T> operator *=(const ConsoleMatr&);
        ConsoleMatr<T> operator *(const ConsoleMatr&);
        virtual void input(std::istream&);
        virtual void output(std::ostream&);
    };
 
    template<class T>
    AbstractMatr<T>::AbstractMatr(size_t n, size_t m)
    {
        Matrix.resize(n);
        for(int i=0; i!=GetRow(); ++i)
        {
            Matrix[i].resize(m);
        }
    }
 
    template<class T>
    AbstractMatr<T>::AbstractMatr(const AbstractMatr<T> &Ob)
    {
        SetSize(Ob.GetRow(), Ob.GetCol());
        for(int i=0; i!=Ob.GetRow(); ++i)
        {
            std::copy(Ob.Matrix[i].begin(), Ob.Matrix[i].end(), Matrix[i].begin());
        }
    }
 
    template<class T>
    void AbstractMatr<T>::SetSize(size_t n, size_t m)
    {
        if(GetRow()!=0&&GetCol()!=0)
            Matrix.clear();
        Matrix.resize(n);
        for(int i=0; i!=GetRow(); ++i)
        {
            Matrix[i].resize(m);
        }
    }
 
    template<class T>
    MathMatr<T>& MathMatr<T>::operator =(const MathMatr<T>& Ob)
    {
        if(this==&Ob)
            return *this;
        SetSize(Ob.GetRow(), Ob.GetCol());
        for(int i=0; i!=GetRow(); ++i)
        {
            std::copy(Ob.Matrix[i].begin(), Ob.Matrix[i].end(), Matrix[i].begin());
        }
        return *this;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator +=(const MathMatr<T>& Ob)
    {
        if(GetRow()!=Ob.GetRow()&&GetCol()!=Ob.GetCol())
           throw std::string("Size of two matrix for sum must be equal!");
        for(int i=0; i!=Ob.GetRow(); ++i)
        {
           for(int j=0; j!=Ob.GetCol(); ++j)
           {
              Matrix[i][j]+=Ob.Matrix[i][j];
           }
        }
        return *this;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator +(const MathMatr<T>& Ob)
    {
        MathMatr<T> Temp(*this);
        Temp+=Ob;
        return Temp;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator *=(const MathMatr<T>& Ob)
    {
    *   if(GetCol()!=Ob.GetRow())
            throw std::string("Num of 1-st matrix cols must be equal to num of 2-nd matrix rows");
        MathMatr Temp(GetRow(), Ob.GetCol());
        for(int i=0; i!=Temp.GetRow(); ++i)
        {
           for(int j=0; j!=Temp.GetCol(); ++j)
           {
              Temp.Matrix[i][j]=0;
              for(int k=0; k!=GetCol(); ++k)
              {
                 Temp.Matrix[i][j]+=Matrix[i][k]*Ob.Matrix[k][j];
              }
            }
        }
        *this=Temp;
        return *this;
    }
 
    template<class T>
    MathMatr<T> MathMatr<T>::operator *(const MathMatr<T>& Ob)
    {
        MathMatr<T> Temp(*this);
        Temp*=Ob;
        return Temp;
    }
 
    template<class T>
    void MathMatr<T>::random_fill()
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
             Matrix[i][j]=1+rand()%50;
          }
       }
    }
 
    template<class T>
    std::ostream& operator <<(std::ostream& os, MathMatr<T>& Ob)
    {
       Ob.output(os);
       return os;
    }
 
    template<class T>
    std::istream& operator >>(std::istream& is, MathMatr<T>& Ob)
    {
       Ob.input(is);
       return is;
    }
 
    template<class T>
    void ConsoleMatr<T>::input(std::istream& is)
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
              std::cout<<"Enter Matrix ["<<i+1<<"]["<<j+1<<"]: ";
              is>>Matrix[i][j];
          }
       }
    }
 
    template<class T>
    void ConsoleMatr<T>::output(std::ostream& os)
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
              os<<std::setw(5)<<Matrix[i][j]<<' ';
          }
          std::cout<<std::endl;
       }
    }
 
    template<class T>
    ConsoleMatr<T>& ConsoleMatr<T>::operator =(const ConsoleMatr<T>& Ob)
    {
        if(this==&Ob)
            return *this;
        SetSize(Ob.GetRow(), Ob.GetCol());
        for(int i=0; i!=GetRow(); ++i)
        {
            std::copy(Ob.Matrix[i].begin(), Ob.Matrix[i].end(), Matrix[i].begin());
        }
        return *this;
    }
 
    template<class T>
    ConsoleMatr<T> ConsoleMatr<T>::operator +=(const ConsoleMatr<T>& Ob)
    {
        if(GetRow()!=Ob.GetRow()&&GetCol()!=Ob.GetCol())
           throw std::string("Size of two matrix for sum must be equal!");
        for(int i=0; i!=Ob.GetRow(); ++i)
        {
           for(int j=0; j!=Ob.GetCol(); ++j)
           {
              Matrix[i][j]+=Ob.Matrix[i][j];
           }
        }
        return *this;
    }
 
    template<class T>
    ConsoleMatr<T> ConsoleMatr<T>::operator +(const ConsoleMatr<T>& Ob)
    {
        ConsoleMatr<T> Temp(*this);
        Temp+=Ob;
        return Temp;
    }
 
    template<class T>
    ConsoleMatr<T> ConsoleMatr<T>::operator *=(const ConsoleMatr<T>& Ob)
    {
        if(GetCol()!=Ob.GetRow())
            throw std::string("Num of 1-st matrix cols must be equal to num of 2-nd matrix rows");
        ConsoleMatr Temp(GetRow(), Ob.GetCol());
        for(int i=0; i!=Temp.GetRow(); ++i)
        {
           for(int j=0; j!=Temp.GetCol(); ++j)
           {
              Temp.Matrix[i][j]=0;
              for(int k=0; k!=GetCol(); ++k)
              {
                 Temp.Matrix[i][j]+=Matrix[i][k]*Ob.Matrix[k][j];
              }
            }
        }
        *this=Temp;
        return *this;
    }
 
    template<class T>
    ConsoleMatr<T> ConsoleMatr<T>::operator *(const ConsoleMatr<T>& Ob)
    {
        ConsoleMatr<T> Temp(*this);
        Temp*=Ob;
        return Temp;
    }
}
#endif


Matrix.cpp
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
#include <vector>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include <string>
 
#include "Matrix.h"
 
int main()
{ 
   using namespace MatrSpace;
   srand(static_cast<unsigned>(time(NULL)));
   ConsoleMatr<int> Ob1;
   size_t row, col;
   std::cout<<"Enter num of rows and cols for 1-st matrix: ";
   std::cin>>row>>col;
   Ob1.SetSize(row, col);
 
   int choise=0;
   std::cout<<"Enter 1 for fill matrix from keyboard\n"
      <<"Enter 2 for random fill matrix\n";
   std::cin>>choise;
   if(choise==1)
      std::cin>>Ob1;
   else if(choise==2)
      Ob1.random_fill();
   else
   {
      std::cerr<<"There is no such option\n";
      return 0;
   }
   std::cout<<std::endl;
   
   ConsoleMatr<int> Ob2;
   std::cout<<"Enter num of rows and cols for 2-nd matrix: ";
   std::cin>>row>>col;
   Ob2.SetSize(row, col);
 
   choise=0;
   std::cout<<"Enter 1 for fill matrix from keyboard\n"
      <<"Enter 2 for random fill matrix\n";
   std::cin>>choise;
   if(choise==1)
      std::cin>>Ob2;
   else if(choise==2)
      Ob2.random_fill();
   else
   {
      std::cerr<<"There is no such option\n";
      return 0;
   }
   std::cout<<std::endl;
 
   ConsoleMatr<int> Ob3;
   std::cout<<"First matrix\n\n"<< Ob1 <<'\n';
   std::cout<<"Second matrix\n\n"<< Ob2 <<'\n';
   try
   {
       Ob3=Ob1*Ob2;
   }
   catch(std::string&str) 
   {
      std::cout<<str<<'\n';
      return 0;
   }
   std::cout<<"Multy of first matrix to second matrix\n\n";
   std::cout<<Ob3<<'\n';
   return 0;
}
alexzak
84 / 57 / 1
Регистрация: 07.08.2010
Сообщений: 185
28.09.2010, 07:02     Абстрактный шаблонный класс #28
Пара замечаний к реализации:
Цитата Сообщение от Lavroff Посмотреть сообщение
C++
1
2
3
4
ConsoleMatr<T> operator +=(const ConsoleMatr&);
ConsoleMatr<T> operator +(const ConsoleMatr&);
ConsoleMatr<T> operator *=(const ConsoleMatr&);
ConsoleMatr<T> operator *(const ConsoleMatr&);
operator += и operator *= должны возвращать ConsoleMatr<T>&, а operator+ и operator* могут и должны быть const. И вообще, везде где ты возвращаешь *this, тип возвращаемого значения с большой вероятностью будет ссылкой.
C++
1
2
3
4
5
        template<class T>
        MathMatr<T>& MathMatr<T>::operator =(const MathMatr<T>& Ob)
        {
                if(this==&Ob)
                        return *this;
Оператор присваивания, который делает проверку на само-присваивание, с большой вероятностью не является exception-safe. И действительно, если в вызове SetSize произойдет исключение, то объект окажется в несколько странном состоянии.

Гораздо более надежной и простой является следующая реализация operator=:
C++
1
2
3
4
5
6
MathMatr & operator=(const MathMatr & other)
{
    MathMatr cpy(other);  // may throw
    cpy.swap(*this);  // can't throw
    return *this;
}
Причем swap должен быть небросающим. В твоем случае такой swap реализуется элементарно:
C++
1
2
3
4
void swap(MathMatr & other)
{
    Matrix.swap(other.Matrix);
}
C++
1
throw std::string("Size of two matrix for sum must be equal!");
Вместо выбрасывания просто строки было бы гораздо лучше использовать один из стандартных классов исключений. Например, сюда больше подойдет invalid_argument из stdexcept.
Mr.X
Эксперт С++
 Аватар для Mr.X
2803 / 1579 / 247
Регистрация: 03.05.2010
Сообщений: 3,670
28.09.2010, 11:49     Абстрактный шаблонный класс #29
Может быть в файле Matrix.h в строке 82 вместо
C++
1
2
3
4
5
6
7
8
9
    template<class T>
    AbstractMatr<T>::AbstractMatr(const AbstractMatr<T> &Ob)
    {
            SetSize(Ob.GetRow(), Ob.GetCol());
            for(int i=0; i!=Ob.GetRow(); ++i)
            {
                    std::copy(Ob.Matrix[i].begin(), Ob.Matrix[i].end(), Matrix[i].begin());
            }
    }
просто написать
C++
1
2
3
4
5
    template<class T>
    AbstractMatr<T>::AbstractMatr(const AbstractMatr<T> &Ob)
    {
        Matrix = Ob.Matrix;
    }
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
28.09.2010, 12:34  [ТС]     Абстрактный шаблонный класс #30
alexzak, То есть. Оперы должны выглядить примерно так?

C++
1
2
3
4
ConsoleMatr<T>& operator +=(const ConsoleMatr&);
const ConsoleMatr<T> operator +(const ConsoleMatr&) const;
ConsoleMatr<T>& operator *=(const ConsoleMatr&);
const ConsoleMatr<T> operator *(const ConsoleMatr&) const;
C++
1
2
3
4
MathMatr & operator=(const MathMatr & other)
{
    MathMatr cpy(other);  // may throw - копирование я так понимаю?
}
C++
1
2
3
4
void swap(MathMatr & other)
{
    Matrix.swap(other.Matrix);
}
Что должен делать этот метод? Менять значения двух объектов?
Mr.X
Эксперт С++
 Аватар для Mr.X
2803 / 1579 / 247
Регистрация: 03.05.2010
Сообщений: 3,670
28.09.2010, 12:43     Абстрактный шаблонный класс #31
Цитата Сообщение от Lavroff Посмотреть сообщение
Нормальный код?
Вообще-то специалисты советуют предпочитать включение наследованию, как более слабую зависимость.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
28.09.2010, 12:48  [ТС]     Абстрактный шаблонный класс #32
Mr.X, Верю. Но мне нужно именно наследование в данной задаче.
Mr.X
Эксперт С++
 Аватар для Mr.X
2803 / 1579 / 247
Регистрация: 03.05.2010
Сообщений: 3,670
28.09.2010, 12:53     Абстрактный шаблонный класс #33
Цитата Сообщение от alexzak Посмотреть сообщение
operator += и operator *= должны возвращать ConsoleMatr<T>&
Скорее const ConsoleMatr<T>&, так как эти операторы не должны возвращать l-value.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
28.09.2010, 19:47  [ТС]     Абстрактный шаблонный класс #34
Итак... Я вообщем-то все изменил. Все работает впринципе.
Matrix.h

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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#ifndef _MATRIX_H_
#define _MATRIX_H_
 
namespace MatrSpace
{
    //Matrix container class
    template<class T>
    class AbstractMatr
    {
    public:
        AbstractMatr() {}
        AbstractMatr(size_t n, size_t m);
        AbstractMatr(const AbstractMatr&);
        virtual ~AbstractMatr() {}
        void SetSize(size_t n, size_t m);
        inline const size_t GetRow() const {return Matrix.size();}
        inline const size_t GetCol() const {return Matrix[0].size();}
        void swap(AbstractMatr&);
    protected:
        std::vector<std::vector<T> > Matrix;
    };
 
    //Math Matr. public from AbstractMatr
    template<class T>
    class MathMatr:public AbstractMatr<T>
    {
    public:
        MathMatr():AbstractMatr() {}
        MathMatr(size_t n, size_t m):AbstractMatr<T>(n, m) {}
        MathMatr(const AbstractMatr<T>& Ob):AbstractMatr<T>(Ob) {}
        virtual ~MathMatr() {}
        const MathMatr<T>& operator =(const MathMatr&);
        const MathMatr<T>& operator +=(const MathMatr&);
        const MathMatr<T> operator +(const MathMatr&) const;
        const MathMatr<T>& operator *=(const MathMatr&);
        const MathMatr<T> operator *(const MathMatr&) const;
        virtual void input(std::istream&) {}
        virtual void output(std::ostream&) const {}
        template<class T2>
        friend std::ostream& operator <<(std::ostream&, const MathMatr<T2>& Ob);
        template<class T2>
        friend std::istream& operator >>(std::istream&, MathMatr<T2>& Ob);
        void random_fill();
    };
 
    //InOutMatr class. Public from MathMatr
    template<class T>
    class IOMatr:public MathMatr<T>
    {
    public:
        IOMatr():MathMatr<T>() {}
        IOMatr(size_t n, size_t m):MathMatr(n, m) {}
        IOMatr(const AbstractMatr<T>& Ob):MathMatr(Ob) {}
        virtual ~IOMatr() {}
        virtual void input(std::istream&)=0;
        virtual void output(std::ostream&) const=0;
    };
 
    //Console InOut public from IOMatr
    template<class T>
    class ConsoleMatr:public IOMatr<T>
    {
    public:
        ConsoleMatr():IOMatr<T>() {}
        ConsoleMatr(size_t n, size_t m):IOMatr(n, m) {}
        ConsoleMatr(const AbstractMatr<T>& Ob):IOMatr(Ob) {}
        virtual ~ConsoleMatr() {}
        const ConsoleMatr<T>& operator =(const ConsoleMatr&);
        const ConsoleMatr<T>& operator +=(const ConsoleMatr&);
        const ConsoleMatr<T> operator +(const ConsoleMatr&) const;
        const ConsoleMatr<T>& operator *=(const ConsoleMatr&);
        const ConsoleMatr<T> operator *(const ConsoleMatr&) const;
        virtual void input(std::istream&);
        virtual void output(std::ostream&) const;
    };
    
    //AbstractMatr func-members
    template<class T>
    AbstractMatr<T>::AbstractMatr(size_t n, size_t m)
    {
        Matrix.resize(n);
        for(int i=0; i!=GetRow(); ++i)
        {
            Matrix[i].resize(m);
        }
    }
 
    template<class T>
    AbstractMatr<T>::AbstractMatr(const AbstractMatr<T> &Ob)
    {
        *this=Ob;
    }
 
    template<class T>
    void AbstractMatr<T>::SetSize(size_t n, size_t m)
    {
        if(GetRow()!=0&&GetCol()!=0)
            Matrix.clear();
        Matrix.resize(n);
        for(int i=0; i!=GetRow(); ++i)
        {
            Matrix[i].resize(m);
        }
    }
 
    template<class T>
    void AbstractMatr<T>::swap(AbstractMatr<T>& Ob)
    {
        Matrix.swap(Ob.Matrix);
    }
    
    //MathMatr func-membets
    template<class T>
    const MathMatr<T>& MathMatr<T>::operator =(const MathMatr<T>& Ob)
    {
        MathMatr<T> Temp(Ob);
        Temp.swap(*this);
        return *this;
    }
 
    template<class T>
    const MathMatr<T>& MathMatr<T>::operator +=(const MathMatr<T>& Ob)
    {
        if(GetRow()!=Ob.GetRow()&&GetCol()!=Ob.GetCol())
            throw std::invalid_argument("Size of two matrix for sum must be equal!");
        for(int i=0; i!=Ob.GetRow(); ++i)
        {
           for(int j=0; j!=Ob.GetCol(); ++j)
           {
              Matrix[i][j]+=Ob.Matrix[i][j];
           }
        }
        return *this;
    }
 
    template<class T>
    const MathMatr<T> MathMatr<T>::operator +(const MathMatr<T>& Ob) const
    {
        MathMatr<T> Temp(*this);
        Temp+=Ob;
        return Temp;
    }
 
    template<class T>
    const MathMatr<T>& MathMatr<T>::operator *=(const MathMatr<T>& Ob)
    {
        if(GetCol()!=Ob.GetRow())
            throw std::invalid_argument("Num of 1-st matrix cols must be equal to num of 2-nd matrix rows");
        MathMatr Temp(GetRow(), Ob.GetCol());
        for(int i=0; i!=Temp.GetRow(); ++i)
        {
           for(int j=0; j!=Temp.GetCol(); ++j)
           {
              Temp.Matrix[i][j]=0;
              for(int k=0; k!=GetCol(); ++k)
              {
                 Temp.Matrix[i][j]+=Matrix[i][k]*Ob.Matrix[k][j];
              }
            }
        }
        *this=Temp;
        return *this;
    }
 
    template<class T>
    const MathMatr<T> MathMatr<T>::operator *(const MathMatr<T>& Ob) const
    {
        MathMatr<T> Temp(*this);
        Temp*=Ob;
        return Temp;
    }
 
    template<class T>
    void MathMatr<T>::random_fill()
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
             Matrix[i][j]=1+rand()%50;
          }
       }
    }
 
    template<class T>
    std::ostream& operator <<(std::ostream& os, const MathMatr<T>& Ob)
    {
       Ob.output(os);
       return os;
    }
 
    template<class T>
    std::istream& operator >>(std::istream& is, MathMatr<T>& Ob)
    {
       Ob.input(is);
       return is;
    }
    
    //ConsoleMatr func-members
    template<class T>
    void ConsoleMatr<T>::input(std::istream& is)
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
              std::cout<<"Enter Matrix ["<<i+1<<"]["<<j+1<<"]: ";
              is>>Matrix[i][j];
          }
       }
    }
 
    template<class T>
    void ConsoleMatr<T>::output(std::ostream& os) const
    {
       for(int i=0; i!=GetRow(); ++i)
       {
          for(int j=0; j!=GetCol(); ++j)
          {
              os<<std::setw(5)<<Matrix[i][j]<<' ';
          }
          std::cout<<std::endl;
       }
    }
 
    template<class T>
    const ConsoleMatr<T>& ConsoleMatr<T>::operator =(const ConsoleMatr<T>& Ob)
    {
        ConsoleMatr Temp(Ob);
        Temp.swap(*this);
        return *this;
    }
 
    template<class T>
    const ConsoleMatr<T>& ConsoleMatr<T>::operator +=(const ConsoleMatr<T>& Ob)
    {
        if(GetRow()!=Ob.GetRow()&&GetCol()!=Ob.GetCol())
           throw std::invalid_argument("Size of two matrix for sum must be equal!");
        for(int i=0; i!=Ob.GetRow(); ++i)
        {
           for(int j=0; j!=Ob.GetCol(); ++j)
           {
              Matrix[i][j]+=Ob.Matrix[i][j];
           }
        }
        return *this;
    }
 
    template<class T>
    const ConsoleMatr<T> ConsoleMatr<T>::operator +(const ConsoleMatr<T>& Ob) const
    {
        ConsoleMatr<T> Temp(*this);
        Temp+=Ob;
        return Temp;
    }
 
    template<class T>
    const ConsoleMatr<T>& ConsoleMatr<T>::operator *=(const ConsoleMatr<T>& Ob)
    {
        if(GetCol()!=Ob.GetRow())
            throw std::invalid_argument("Num of 1-st matrix cols must be equal to num of 2-nd matrix rows");
        ConsoleMatr Temp(GetRow(), Ob.GetCol());
        for(int i=0; i!=Temp.GetRow(); ++i)
        {
           for(int j=0; j!=Temp.GetCol(); ++j)
           {
              for(int k=0; k!=GetCol(); ++k)
              {
                 Temp.Matrix[i][j]+=Matrix[i][k]*Ob.Matrix[k][j];
              }
            }
        }
        *this=Temp;
        return *this;
    }
 
    template<class T>
    const ConsoleMatr<T> ConsoleMatr<T>::operator *(const ConsoleMatr<T>& Ob) const
    {
        ConsoleMatr<T> Temp(*this);
        Temp*=Ob;
        return Temp;
    }
}
#endif


Только...
C++
1
2
3
4
5
    template<class T>
    AbstractMatr<T>::AbstractMatr(const AbstractMatr<T> &Ob)
    {
        *this=Ob;
    }
Нормально-ли?
alexzak
84 / 57 / 1
Регистрация: 07.08.2010
Сообщений: 185
29.09.2010, 04:23     Абстрактный шаблонный класс #35
Цитата Сообщение от Lavroff Посмотреть сообщение
Итак... Я вообщем-то все изменил. Все работает впринципе.

Только...
C++
1
2
3
4
5
    template<class T>
    AbstractMatr<T>::AbstractMatr(const AbstractMatr<T> &Ob)
    {
        *this=Ob;
    }
Нормально-ли?
В копирующем конструкторе принято все что можно инициализировать в списке инициализации членов класса. Вот так:
C++
1
2
3
4
template <class T>
AbstractMatr<T>::AbstractMatr(const AbtractMatr<T> & Ob)
    : Matrix(Ob.Matrix)
{}
Добавлено через 13 минут
Цитата Сообщение от Mr.X Посмотреть сообщение
Скорее const ConsoleMatr<T>&, так как эти операторы не должны возвращать l-value.
Зачем возвращать const ConsoleMatr& ? Какой цели это служит? Если ориентироваться на стандартные классы и делать как в них сделано, то там возвращается просто по ссылке. Например, класс complex (http://cplusplus.com/reference/std/c...x/operators/):
C++
1
2
3
4
5
6
*** complex member functions: ***
complex<T>& operator= (const T& val);
complex<T>& operator+= (const T& val);
complex<T>& operator-= (const T& val);
complex<T>& operator*= (const T& val);
complex<T>& operator/= (const T& val);
А остальные операторы - просто по значению (тоже без const):
C++
1
2
*** global functions: ***
template<class T> complex<T> operator+(const complex<T>& lhs, const complex<T>& rhs);
Mr.X
Эксперт С++
 Аватар для Mr.X
2803 / 1579 / 247
Регистрация: 03.05.2010
Сообщений: 3,670
29.09.2010, 17:09     Абстрактный шаблонный класс #36
Цитата Сообщение от alexzak Посмотреть сообщение
Зачем возвращать const ConsoleMatr& ? Какой цели это служит? Если ориентироваться на стандартные классы и делать как в них сделано, то там возвращается просто по ссылке. Например, класс complex (http://cplusplus.com/reference/std/c...x/operators/):
C++
1
2
3
4
5
6
*** complex member functions: ***
complex<T>& operator= (const T& val);
complex<T>& operator+= (const T& val);
complex<T>& operator-= (const T& val);
complex<T>& operator*= (const T& val);
complex<T>& operator/= (const T& val);
А остальные операторы - просто по значению (тоже без const):
C++
1
2
*** global functions: ***
template<class T> complex<T> operator+(const complex<T>& lhs, const complex<T>& rhs);
Ну, здесь я могу сослаться на книгу Скотта Майерса «Эффективное использование C++. 50 рекомендаций…», правило 21 которой называется «Везде, где только можно, используйте const». Там он приводит пример перегрузки оператора
const Rational operator*(const Rational& lhs, const Rational& rhs);
Он мотивирует здесь const тем, что иначе будут возможны вещи, которые он называет надругательством над здравым смыслом:
Rational a, b, c;

(a * b) = c;

Далее он пишет, что один из критериев хорошо определенного пользовательского типа – это отсутствие необоснованной несовместимости с поведением встроенных типов.
alexzak
84 / 57 / 1
Регистрация: 07.08.2010
Сообщений: 185
01.10.2010, 07:11     Абстрактный шаблонный класс #37
Цитата Сообщение от Mr.X Посмотреть сообщение
Ну, здесь я могу сослаться на книгу Скотта Майерса «Эффективное использование C++. 50 рекомендаций…», правило 21 которой называется «Везде, где только можно, используйте const».
Это то место, где он оказался неправ. Скотт Майерс не практик, а скорее "educator" (он изучает новые вещи, относящиеся к С++, а потом создаёт курсы для обучения других). И иногда он выдаёт вот такие "правила", которые с практической точки зрения неприменимы. Вот это его правило не прижилось. Как я помню его пообсуждали в свое время и забыли.
Mr.X
Эксперт С++
 Аватар для Mr.X
2803 / 1579 / 247
Регистрация: 03.05.2010
Сообщений: 3,670
01.10.2010, 09:42     Абстрактный шаблонный класс #38
Цитата Сообщение от alexzak Посмотреть сообщение
Это то место, где он оказался неправ. Скотт Майерс не практик, а скорее "educator" (он изучает новые вещи, относящиеся к С++, а потом создаёт курсы для обучения других). И иногда он выдаёт вот такие "правила", которые с практической точки зрения неприменимы. Вот это его правило не прижилось. Как я помню его пообсуждали в свое время и забыли.
Ну вы уж поясните тогда, в чем он неправ-то. И в чем практическая неприменимость данного правила?
alexzak
84 / 57 / 1
Регистрация: 07.08.2010
Сообщений: 185
02.10.2010, 03:33     Абстрактный шаблонный класс #39
Цитата Сообщение от Mr.X Посмотреть сообщение
Ну вы уж поясните тогда, в чем он неправ-то. И в чем практическая неприменимость данного правила?
Так, понятно дело, в чём неприменимость. Майерс решил биться с ветряными мельницами. От чего он таким образом защищается, - пресловутое (a *= b) = c, - в коде редко когда встречается. А если такой код кто и напишет, то ничего страшного не будет. Всё продолжает работаеть как и предполагалось.

Поэтому в стандарте таких вещей нет. И в широко распостранённых С++ библиотеках тоже.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
02.10.2010, 09:43     Абстрактный шаблонный класс
Еще ссылки по теме:

Шаблонный класс C++
C++ Шаблонный класс
C++ шаблонный класс

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Mr.X
Эксперт С++
 Аватар для Mr.X
2803 / 1579 / 247
Регистрация: 03.05.2010
Сообщений: 3,670
02.10.2010, 09:43     Абстрактный шаблонный класс #40
Цитата Сообщение от alexzak Посмотреть сообщение
Так, понятно дело, в чём неприменимость. Майерс решил биться с ветряными мельницами. От чего он таким образом защищается, - пресловутое (a *= b) = c, - в коде редко когда встречается. А если такой код кто и напишет, то ничего страшного не будет. Всё продолжает работаеть как и предполагалось.

Поэтому в стандарте таких вещей нет. И в широко распостранённых С++ библиотеках тоже.
Однако ж отсюда никак не следует, что Майерс неправ, и что его правило практически неприменимо. Тут скорее спор просто о вкусах. Поэтому ваша категоричность и безапелляционность при их обсуждении не совсем понятна. Мы же с Майерсом считаем, что следует приветствовать любые правила, ведущие к предотвращению ненужных взаимозависимостей, к большей понятности и предсказуемости кода.
Yandex
Объявления
02.10.2010, 09:43     Абстрактный шаблонный класс
Ответ Создать тему
Опции темы

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