Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Как работать с членами класса? Как определить отдельную функцию?  (Прочитано 29539 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Люсь
Команда клуба

ru
Offline Offline
Пол: Женский

« : 12-02-2008 09:35 » 

Всем привет!

У меня такое задание:

Составить программу для умноэения матрицы на вектор. Матрица и вектор задаются в своих класах. Операция умножения производится с использованием отдельного оператора. Данные считываются из файла. Результат записывается в выходной файл.
Размер матрицы 3х3
Размер вектора 1х3
Элемент матрицы - целые числа.

У меня получилось вот что:

Код:
#include <iostream.h>
#include <fstream.h>

struct vector{int el[3];};
struct matrica{int el[3][3];};
struct result{int el[3][3];};

void main()

{

   ifstream mfs("matrica.txt", ios::in);
   if (mfs.is_open())
      {
         cout<<"ok\n";
      } else {
         exit (0);
      }

   ifstream vfs("vector.txt", ios::in);

   ofstream rfs("result.txt", ios::out);

   int i, j;
   for (i=1; i<=3; i++)
   {
      for (j=1; j<=3; j++)
      {
         matrica.el[i][j] = mfs;
         vector.el[i] = vfs;
         result.el[i][j]=matrica.el[i][j]*vector.el[i];
         rfs = result.el[i][j];
         cout << rfs;
      }
   }

   return 0;
}

Но прога не компилится, спотыкаясь на шаге
Код:
matrica.el[i][j] = mfs;
Что я делаю неправильно в обращении к членам класса?

Тестить мне негде, вот это написала пока с компа не выгнали.
Ещё я так и не поняла, как переопределять функцию?

Жду помощи.
« Последнее редактирование: 12-02-2008 09:43 от Люсь » Записан

Посторонним просьба не беспокоить!
-------------------------------------------------
O (I) Rh +
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 12-02-2008 10:03 » 

Вот исправленный вариант. На непогрешимость не претендую, но работает и результат на тесте нормальный выводит:

Код:
#include "stdafx.h"
#include <iostream>
#include <fstream>

struct vector{int el[3];};
struct matrica{int el[3][3];};
struct result{int el[3][3];};
using namespace std;

void main()
{
    vector vec;
    matrica matr;
    result res;
    ifstream mfs("matrica.txt", ios::in);
    if (mfs.is_open())
    {
        cout<<"ok\n";
    } else {
        exit (0);
    }

    ifstream vfs("vector.txt", ios::in);

    ofstream rfs("result.txt", ios::out);

    int i, j;
    for (i=0; i<=2; i++)
    {
        vfs >> vec.el[i];
        for (j=0; j<=2; j++)
        {
            mfs >> matr.el[i][j] ;
           
            res.el[i][j]=matr.el[i][j]*vec.el[i];
            rfs << res.el[i][j] << "  ";
            cout << res.el[i][j] << "  " ;
        }
        cout << endl;
        rfs << endl;
    }
    mfs.close();
    vfs.close();
    rfs.close();
    return;
}

Ошибки:
1) matrica etc - это типы, использовать в вычислениях нужно объекты (экземпляры) типов (они объявлены у меня в первых строках main).
2) чтение из стримов - см. как у меня. К тому же, вектор считывался внутри 2го цикла (то есть, пытались считать 9 значений вместо 3х)
3) номерация массивов в С++ всегда начинается с 0, поэтому в циклах i,j 0..2. Старый вариант приводил бы к ошибкам при выполнении.
Остальное - по мелочи, разделил пробелами вывод в стрим, добавил перевод строк и закрытие самих потоков ввода-вывода.
« Последнее редактирование: 12-02-2008 10:12 от Вад » Записан
Люсь
Команда клуба

ru
Offline Offline
Пол: Женский

« Ответ #2 : 12-02-2008 10:11 » 

Спасибо, будет доступ - разберусь.
А как насчёт переопределённой функции умножения матрицы на вектор? Выделила в задании это место жирным шрифтом.
Записан

Посторонним просьба не беспокоить!
-------------------------------------------------
O (I) Rh +
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 12-02-2008 10:24 » 

Вот самый простой вариант с переопределением, сделанный на коленке Улыбаюсь Опять же, на эталонность не претендую, пусть меня поправят, если что не так. Но код рабочий.
Код:
#include "stdafx.h"
#include <iostream>
#include <fstream>
using namespace std;

struct vector{int el[3];};
struct matrica{
    int el[3][3];
    matrica operator*(vector& vec)
    {
        matrica res;
        for (int i=0; i<3; i++)
        {
            for (int j=0; j<3; j++)
            {
                res.el[i][j]=el[i][j]*vec.el[i];
            }
        }
        return res;
    };
};

void main()
{
    vector vec;
    matrica matr;
    matrica res;
    ifstream mfs("matrica.txt", ios::in);
    if (mfs.is_open())
    {
        cout<<"ok\n";
    } else {
        exit (0);
    }

    ifstream vfs("vector.txt", ios::in);

    ofstream rfs("result.txt", ios::out);

    int i, j;
    for (i=0; i<=2; i++)
    {
        vfs >> vec.el[i];
        for (j=0; j<=2; j++)
        {
            mfs >> matr.el[i][j] ;
        }
    }

    // multiply matrix by vector
    res = matr * vec;

    for (i=0; i<=2; i++)
    {
        for (j=0; j<=2; j++)
        {
            res.el[i][j]=matr.el[i][j]*vec.el[i];
            rfs << res.el[i][j] << "  ";
            cout << res.el[i][j] << "  " ;
        }
        cout << endl;
        rfs << endl;
    }
    mfs.close();
    vfs.close();
    rfs.close();
    return;
}

Поскольку результат - такая же матрица 3*3, как и исходная, то я упразднил лишний тип. Видно, что оператор принимает в качестве параметра вектор, внутри создаётся новая матрица, в которую считаем произведение, и возвращаем её.
Записан
Sands
Помогающий

ua
Offline Offline

« Ответ #4 : 12-02-2008 10:41 » 

1) Я, конечно, не претендую на единственно правильное мнение, но ИМХО матрица на вектор умножается не так, как ето реализовано в данных листингах. Потому как
A*x = y
A={a[ i ][j]} i = 1..n, j = 1..m; x={x[j]}, j=1..m; y = {y[ i ]} i = 1..n
при етом
y[ i ]=sum(a[ i ][j]*x[j])
Сразу оговорюсь, что для матрицы i - количество строк, j - количество столбцов
2) Для реализации операции умножения отдельным оператором необходимо перегрузить оператор умножения(прошу прощения за каламбур). Сделать етоможно двумя способами - либо обьявить етот оператор методом класса либо friend-функцией
семантика обьявления
vector operator *(matrix a, vector b);
3) У тебя в задании значится что матрица и вектор должны быть классами, а ты пока только структуры реализовала - подумай об етом. И еще <матрица>*<вектор>=<вектор> а ты еще и дополнительный тип для результата ввела, изилшество выходит )).

З.Ы Пока писал тебе уже и оператор переопределили ))
Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 12-02-2008 11:07 » 

Да, я вот тоже сижу думаю, что с умножением я что-то намудрил - опирался на исходный листинг Улыбаюсь
По сути, модификация сводится к изменению оператора, чтобы он вычислял вектор, как написал Sands, и возвращал его же.
А между структурами и классами не столь уж большая разница Улыбаюсь назвать это всё class и расставить private и public. Разве вот только придётся сделать некоторый метод для установки значений элементам векторов и матриц, чтобы не напрямую к свойствам объекта обращаться, а как положено Улыбаюсь
Записан
Люсь
Команда клуба

ru
Offline Offline
Пол: Женский

« Ответ #6 : 12-02-2008 11:57 » 

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

Как именно матрица на вектор перемножается - не суть важно, если вдруг перпендикулярно моему способу - проще пареной репы i заменить на j. Просто когда я искала определение вектора - я такого вообще не нашла относительно числового массива. Был метод перемножения двух матриц, исходя из чего я решила матрицу 1х3 считать вектором. Но как именно перемножать - параллельно или перпендикулярно - мне не было определено, решение пришлось принимать самой.

Надеюсь, мне самой понятно, чё я сказала Улыбаюсь)))

Вад, ага, я тоже разницы пока не чувствую.
Жаль, помучить препода мало придётся. Мне почему-то приятнее усваивать знания от чуткого преподавателя, а не из книжки с непонятными заданиями Улыбаюсь

С перегрузкой оператора всё же пока не очень понятно...
Записан

Посторонним просьба не беспокоить!
-------------------------------------------------
O (I) Rh +
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 12-02-2008 12:19 » 

Разница только в том, что в структурах по умолчанию разрешён доступ извне ко всем полям (свойствам) - это используется в примере. Всё равно, что в начале определения класса написать public:
А так класс - та же завуалированная структура Улыбаюсь

Что касается перегрузки оператора, то в приведённом решении будет так: оператор * - это метод, вызываемый для матрицы (она стоит слева от *, соответственно), в него передаётся параметр, стоящий справа (чтобы не копировать, принимаем его по ссылке). Далее, поскольку оператор - это метод структуры (класса) matrica, то он имеет непосредственный доступ к содержимому объекта, для которого был вызван (поэтому в правой части умножения просто el[ i ][ j ]). Ну и наконец, возвращаем новый объект - другую матрицу (а нужно - значение типа вектор, как верно заметил Sands), чтобы наше умножение не изменяло значение текущих участвующих в операции объектов (нам ведь этого не нужно - когда мы умножаем, скажем, int на int, значения перемножаемых переменных не меняются).
В общем, описать такой оператор - почти то же самое, что задать некоторую внешнюю функцию, которая у себя внутри умножает матрицу на вектор и возвращает результат, с той лишь разницей, что внешняя функция будет принимать два параметра явно, а оператор принимает первый параметр неявно, при этом получая прямой доступ к элементам этого первого операнда.
« Последнее редактирование: 12-02-2008 12:22 от Вад » Записан
Люсь
Команда клуба

ru
Offline Offline
Пол: Женский

« Ответ #8 : 12-02-2008 12:29 » new

фух, сложности какие...
ладно, вся жизнь впереди Улыбаюсь
жаль только, что учить начинают сначала по одному (процедурное), а потом бац - и надо переучиваться, потому что так делают все, - и ни фига непонятно на базе полученных знаний...
Записан

Посторонним просьба не беспокоить!
-------------------------------------------------
O (I) Rh +
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 12-02-2008 12:36 » 

Тут пришло в голову, что, возможно, описание принципа действия оператора * будет несколько нагляднее, если упомянуть, что альтернативная форма вызова этого метода выглядит так:
Код:
res = matr.operator*(vec);
Записан
Люсь
Команда клуба

ru
Offline Offline
Пол: Женский

« Ответ #10 : 12-02-2008 12:54 » 

Спасибо, я щас распечатаю, дома попробую докопаться до сути.
Записан

Посторонним просьба не беспокоить!
-------------------------------------------------
O (I) Rh +
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #11 : 12-02-2008 13:33 » 

Люсь, поздравляю с посвящением в ООП. Ага
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Sands
Помогающий

ua
Offline Offline

« Ответ #12 : 12-02-2008 18:01 » 

Люсь, я к тому писал про умножение матриц, что есть отдельная категория преподавателей, которые лабораторки(ну или еще какие вещи для контроля за знаниями) проверяют не чтением кода, а "листиком". Тоесть у него есть вход и выход, так вот в твоем случае даже если ты правильно все сделаеш но умножение будет реализовано неправильно, то твой выход не совпадет с требуемым, и будет очень трудно доказать что ты не верблюд )))
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #13 : 12-02-2008 21:53 » 

Я бы для такой задачи сделал класс матрицы, написал бы умножение матриц, а вектор сделал бы частным случаем матрицы - производным от матрицы классом.

Вместе с тестом у меня получилось так:
Код: (C++)
#include <iostream>
#include <exception>

using namespace std;

class ArgumentException: public exception {};
class InternalError: public exception {};

class Matrix {
        int _rows, _columns;
        int *_ptr_items;
        int _size() const {
                return _rows * _columns;
        }
        int _index(int row, int column) const throw(ArgumentException) {
                if(row <= 0 || row > _rows || column <= 0 || column > _columns)
                        throw ArgumentException();
                return (row - 1) * _columns + (column - 1);
        }
public:
        Matrix(int rows, int columns) throw(ArgumentException) {
                if(rows <= 0 || columns <= 0)
                        throw ArgumentException();
                _rows = rows;
                _columns = columns;
                _ptr_items = new int[_size()];
        }
        virtual ~Matrix() {
                delete _ptr_items;
        }
        int getRows() const {
                return _rows;
        }
        int getColumns() const {
                return _columns;
        }
        int getItem(int row, int column) const throw(ArgumentException) {
                return _ptr_items[_index(row, column)];
        }
        void setItem(int row, int column, int value) throw(ArgumentException) {
                _ptr_items[_index(row, column)] = value;
        }
};

Matrix operator*(const Matrix &m1, const Matrix &m2) throw(ArgumentException, InternalError) {
        if(m1.getColumns() != m2.getRows())
                throw ArgumentException();
        Matrix result(m1.getRows(), m2.getColumns());
        for(int i = 1; i <= m1.getRows(); ++i)
                for(int j = 1; j <= m2.getColumns(); ++j) {
                        int item = 0;
                        for(int k = 1; k <= m1.getColumns(); ++k)
                                try {
                                        item += m1.getItem(i, k) * m2.getItem(k, j);
                                } catch(ArgumentException) {
                                        throw InternalError();
                                }
                        try {
                                result.setItem(i, j, item);
                        } catch(ArgumentException) {
                                throw InternalError();
                        }
                }
        return result;
}

class Vector: public Matrix {
public:
        Vector(int size) throw(ArgumentException):
                Matrix(size, 1)
        {}
        int getSize() const {
                return Matrix::getRows();
        }
        int getItem(int index) const throw(ArgumentException) {
                return Matrix::getItem(index, 1);
        }
        void setItem(int index, int value) throw(ArgumentException) {
                return Matrix::setItem(index, 1, value);
        }
};

void printMatrix(const Matrix &m) {
        for(int i = 1; i <= m.getRows(); ++i) {
                for(int j = 1; j <= m.getColumns(); ++j)
                        cout << m.getItem(i, j) << " ";
                cout << endl;
        }
}

int main() {
        try {
                cout << "Матрица" << endl;
                Matrix a(2, 2);
                a.setItem(1, 1, 1);
                a.setItem(1, 2, 2);
                a.setItem(2, 1, 3);
                a.setItem(2, 2, 4);
                printMatrix(a);

                cout << "умножается на вектор" << endl;
                Vector b(2);
                b.setItem(1, 5);
                b.setItem(2, 6);
                printMatrix(b);

                Matrix c = a * b;
                cout << "результат" << endl;
                printMatrix(c);

                if(c.getItem(1, 1) == 17 && c.getItem(2, 1) == 39)
                        cout << "ВЕРНО" << endl;
                else
                        cout << "НЕВЕРНО" << endl;
        } catch(ArgumentException) {
                cout << "ОШИБКА ПРОГРАММИРОВАНИЯ" << endl;
        } catch(InternalError) {
                cout << "ОШИБКА ПРОГРАММИРОВАНИЯ" << endl;
        }
}
А ещё можно int в матрице заменить на шаблонный тип <class T>, чтобы и вещественные числа охватить, и определяемые пользователем числа, поддерживающие операции + и *.
« Последнее редактирование: 12-02-2008 21:55 от dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 12-02-2008 22:33 » 

dimka, в классе Vector тогда лучше бы сделать 2й параметр конструктора, определяющий, что это: вектор-столбец или вектор-строка. В противном случае можно будет умножать вектор на матрицу только с одной стороны.
А ещё, меня смущает отсутствие конструктора копирования для класса Matrix (конструктор копирования по умолчанию будет копировать значение указателя _ptr_items, что будет приводить к проблемам с использованием памяти):
Код:
    Matrix(const Matrix &parent){
        _rows = parent._rows;
        _columns = parent._columns;
        _ptr_items = new int[_size()];
        memcpy(_ptr_items, parent._ptr_items, sizeof(int)*_size());
    }

Вектор с реализацией "столбцов" и "строк" (набросок на основе вышеприведённого):
Код:
class Vector: public Matrix {
    bool _column;
public:
Vector(int size, bool column = true) throw(ArgumentException):
           Matrix(column ? size : 1, column ? 1 : size),
           _column(column)
{}

int getSize() const {
        return _column ? Matrix::getRows() : Matrix::getColumns();
}
int getItem(int index) const throw(ArgumentException) {
        return Matrix::getItem(_column ? index : 1, _column ? 1 : index);
}
void setItem(int index, int value) throw(ArgumentException) {
        return Matrix::setItem(_column ? index : 1, _column ? 1 : index, value);
}
};
тогда можно будет делать так:
Код:
Matrix a(2, 2);
a.setItem(1, 1, 1);
a.setItem(1, 2, 2);
a.setItem(2, 1, 3);
a.setItem(2, 2, 4);
printMatrix(a);

// умножение матрицы на вектор справа, по умолчанию создаём вектор-столбец:
Vector b(2);
b.setItem(1, 5);
b.setItem(2, 6);
printMatrix(b);
// само умножение
Matrix c = a * b;
printMatrix(c);

// умножение на вектор слева, создаём вектор-строку:
Vector d(2, false);
d.setItem(1, 5);
d.setItem(2, 6);
printMatrix(d);
// второе умножение
Matrix e = d * a;
printMatrix(e);
« Последнее редактирование: 12-02-2008 22:37 от Вад » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 13-02-2008 08:37 » 

Вад, согласен и с конструктором, и усовершенствованием вектора.

Разве что для пущей читабельности кода булевый атрибут лучше заменить на значение типа
Код: (C++)
enum VectorOrientation { COLUMN, ROW };

Меня ещё смущает возврат значения типа Matrix из оператора умножения. Терзают меня подозрения, что там один раз выполняется копирование матрицы. Ссылку туда не подставить. А с указателями не так элегантно будет: пользователю оператора придётся возиться с выделением и очисткой памяти.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #16 : 13-02-2008 08:48 » 

Ещё я в main забыл return 0 написать, а комплиятор даже не заикнулся.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #17 : 13-02-2008 19:14 » 

Ещё хорошо бы в конструктор матрицы передавать значение, которое элементы матрицы принимают по умолчанию при инициализации. Это особенно актуально при использовании шаблонов.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #18 : 13-02-2008 20:31 » 

После учёта разных замечаний улучшенная версия получилась такой:
Код: (C++)
#include <cstdlib>
#include <iostream>
#include <exception>

using namespace std;

class ArgumentException: public exception {};
class InternalError: public exception {};

template<class T>
class Matrix;

template<class T>
Matrix<T> operator*(const Matrix<T> &m1, const Matrix<T> &m2) throw(ArgumentException, InternalError) {
        if(m1.getColumns() != m2.getRows())
                throw ArgumentException();
        Matrix<T> result(m1.getRows(), m2.getColumns());
        for(int i = 1; i <= m1.getRows(); ++i)
                for(int j = 1; j <= m2.getColumns(); ++j) {
                        T item = 0;
                        for(int k = 1; k <= m1.getColumns(); ++k)
                                try {
                                        item += m1.getItem(i, k) * m2.getItem(k, j);
                                } catch(ArgumentException) {
                                        throw InternalError();
                                }
                        try {
                                result.setItem(i, j, item);
                        } catch(ArgumentException) {
                                throw InternalError();
                        }
                }
        return result;
}

template<class T>
class Matrix {
        friend Matrix<T> operator*<T>(const Matrix<T> &, const Matrix<T> &);
        int _rows, _columns;
        T *_ptr_items;
        int _size() const {
                return _rows * _columns;
        }
        int _index(int row, int column) const throw(ArgumentException) {
                if(row <= 0 || row > _rows || column <= 0 || column > _columns)
                        throw ArgumentException();
                return (row - 1) * _columns + (column - 1);
        }
        void _init(int rows, int columns) throw(ArgumentException) {
                if(rows <= 0 || columns <= 0)
                        throw ArgumentException();
                _rows = rows;
                _columns = columns;
                _ptr_items = new T[_size()];
        }
        Matrix(int rows, int columns) throw(ArgumentException) {
                _init(rows, columns);
        }
public:
        Matrix(int rows, int columns, const T defaultValue) throw(ArgumentException) {
                _init(rows, columns);
                for(int i = 0; i < _size(); ++i)
                        _ptr_items[i] = defaultValue;          
        }
        Matrix(const Matrix &other) {
                _rows = other._rows;
                _columns = other._columns;
                memcpy(_ptr_items, other._ptr_items, _size() * sizeof(T));
        }
        virtual ~Matrix() {
                delete _ptr_items;
        }
        int getRows() const {
                return _rows;
        }
        int getColumns() const {
                return _columns;
        }
        T getItem(int row, int column) const throw(ArgumentException) {
                return _ptr_items[_index(row, column)];
        }
        void setItem(int row, int column, T value) throw(ArgumentException) {
                _ptr_items[_index(row, column)] = value;
        }
};

template<class T>
class Vector: public Matrix<T> {
public:
        enum Orientation {
                ROW, COLUMN
        };
private:
        Orientation _orientation;
        int _getRows(int size, Orientation orientation) const {
                switch(orientation) {
                case ROW:
                        return 1;
                case COLUMN:
                        return size;
                default:
                        throw InternalError();
                }
        }
        int _getColumns(int size, Orientation orientation) const {
                switch(orientation) {
                case ROW:
                        return size;
                case COLUMN:
                        return 1;
                default:
                        throw InternalError();
                }
        }
public:
        Vector(int size, const T defaultValue, Orientation orientation) throw(ArgumentException, InternalError):
                        Matrix<T>(_getRows(size, orientation), _getColumns(size, orientation), defaultValue),
                        _orientation(orientation) {
        }
        int getSize() const throw(InternalError) {
                switch(_orientation) {
                case ROW:
                        return Matrix<T>::getColumns();
                case COLUMN:
                        return Matrix<T>::getRows();
                default:
                        throw InternalError();
                }
        }
        T getItem(int index) const throw(ArgumentException, InternalError) {
                switch(_orientation) {
                case ROW:
                        return Matrix<T>::getItem(1, index);
                case COLUMN:
                        return Matrix<T>::getItem(index, 1);
                default:
                        throw InternalError();
                }
        }
        void setItem(int index, T value) throw(ArgumentException, InternalError) {
                switch(_orientation) {
                case ROW:
                        Matrix<T>::setItem(1, index, value);
                        break;
                case COLUMN:
                        Matrix<T>::setItem(index, 1, value);
                        break;
                default:
                        throw InternalError();
                }
        }
};

template<class T>
void printMatrix(const Matrix<T> &m) {
        for(int i = 1; i <= m.getRows(); ++i) {
                for(int j = 1; j <= m.getColumns(); ++j)
                        cout << m.getItem(i, j) << " ";
                cout << endl;
        }
}

int main() {
        try {
                cout << "Матрица" << endl;
                Matrix<int> a(2, 2, 0);
                a.setItem(1, 1, 1);
                a.setItem(1, 2, 2);
                a.setItem(2, 1, 3);
                a.setItem(2, 2, 4);
                printMatrix<int>(a);

                typedef Vector<int> MyVector;

                cout << "умножается на вектор" << endl;
                MyVector b(2, 0, MyVector::COLUMN);
                b.setItem(1, 5);
                b.setItem(2, 6);
                printMatrix<int>(b);

                Matrix<int> c = a * b;
                cout << "результат" << endl;
                printMatrix<int>(c);

                if(c.getItem(1, 1) == 17 && c.getItem(2, 1) == 39)
                        cout << "ВЕРНО" << endl;
                else
                        cout << "НЕВЕРНО" << endl;

                cout << "Вектор" << endl;
                MyVector d(2, 0, MyVector::ROW);
                d.setItem(1, 5);
                d.setItem(2, 6);
                printMatrix<int>(d);

                cout << "умножается на матрицу" << endl;
                printMatrix<int>(a);

                Matrix<int> e = d * a;
                cout << "результат" << endl;
                printMatrix<int>(e);

                if(e.getItem(1, 1) == 23 && e.getItem(1, 2) == 34)
                        cout << "ВЕРНО" << endl;
                else
                        cout << "НЕВЕРНО" << endl;

        } catch(ArgumentException) {
                cout << "ОШИБКА ПРОГРАММИРОВАНИЯ" << endl;
        } catch(InternalError) {
                cout << "ОШИБКА ПРОГРАММИРОВАНИЯ" << endl;
        }
        return 0;
}
Оператор умножения объявлен другом для доступа к закрытому конструктору, который не инициализирует новую матрицу значениями по умолчанию, поскольку в результате умножения и так все элементы матрицы будут определены. Для пользователя такая возможность закрыта.
« Последнее редактирование: 13-02-2008 20:35 от dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Scorp__)
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #19 : 13-02-2008 20:57 » 

Offtopic:
Ну вот как всегда Улыбаюсь) Вместо объяснения увлеклись и решили за человека задачу. Теперь Люсе еще одну надо, чтобы все-таки научиться Улыбаюсь)
Поставлю в угол.
Записан

- А Вы сами-то верите в привидения?
- Конечно, нет, - ответил лектор и медленно растаял в воздухе.
Люсь
Команда клуба

ru
Offline Offline
Пол: Женский

« Ответ #20 : 14-02-2008 05:01 » 

Scorp__), точно Улыбаюсь
Пока читала, у меня было такое ощущение, что ещё чуть-чуть - и такое развитие поиска решений может сойти за курсовую Ага
По идее, это я должна была написать
Цитата
После учёта разных замечаний улучшенная версия получилась такой:

Улыбаюсь
« Последнее редактирование: 14-02-2008 09:54 от Джон » Записан

Посторонним просьба не беспокоить!
-------------------------------------------------
O (I) Rh +
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #21 : 14-02-2008 06:43 » 

Люсь, ничего, в приведённой последней версии от dimka ещё можно найти источник дальнейших доработок: так, можно реализовать оператор *=, чтобы можно было делать так:
Код:
Matrix a(x, y);
Matrix b(y, z);
// заполнение матриц
...
a *= b;
То есть, умножать с изменением содержимого первого аргумента. Например, Александреску с Саттером в "Стандартах программирования на C++" советуют в принципе реализовывать operator* через operator*= Хотя, как вспоминаю, была у них оговорка, кажется, как раз насчёт математических структур, дескать, здесь operator*= может быть сложнее, и потому не стоит его использовать при реализации operator*
Так что, тут ещё для деятельности поле непаханое, ну или, скажем так, сильно недопаханое  Ага
« Последнее редактирование: 14-02-2008 07:02 от Вад » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #22 : 14-02-2008 08:45 » 

В задании ещё сказано про файловый ввод и вывод - этого в программе нет, так как интересовала в первую очередь реализация умножения матриц.

И, кстати, использование defaultValue можно обобщить до заполнения матрицы значениями при помощи какого-нибудь внешнего генератора значений. Поскольку присвоение одинакового значения - частный случай присвоения разных значений. Заводится метод типа void setItems(generator), где каждое значение для каждой позиции в матрицы запрашивается у этого генератора.

Через него можно задавать как значения по умолчанию, так и осуществлять ввод данных из файла или от пользователя с консоли, или в GUI-приложении читать какой-нибудь grid.

В общем, работы тут ещё непочатый край Улыбаюсь
« Последнее редактирование: 14-02-2008 08:52 от dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #23 : 14-02-2008 19:03 » 

После внедрения генераторов значений получилось следующее Улыбаюсь
Код: (C++)
#include <cstdlib>
#include <iostream>
#include <exception>

using namespace std;

// Разные исключительные ситуации.
class InvalidArgument: public exception {};
class OperationFailed: public exception {};
class InternalError: public exception {};

// Классы работы с матрицами.
namespace matrix
{
        template<class T>
        class Matrix;

        // Умножение матриц.
        template<class T>
        Matrix<T> operator*(const Matrix<T> &m1, const Matrix<T> &m2) throw(InvalidArgument, InternalError) {
                if(m1.getColumns() != m2.getRows())
                        throw InvalidArgument();
                Matrix<T> result(m1.getRows(), m2.getColumns());
                for(int i = 1; i <= m1.getRows(); ++i)
                        for(int j = 1; j <= m2.getColumns(); ++j) {
                                T item = 0;
                                for(int k = 1; k <= m1.getColumns(); ++k)
                                        try {
                                                item += m1.getItem(i, k) * m2.getItem(k, j);
                                        } catch(InvalidArgument) {
                                                throw InternalError();
                                        }
                                try {
                                        result.setItem(i, j, item);
                                } catch(InvalidArgument) {
                                        throw InternalError();
                                }
                        }
                return result;
        }

        // Матрица.
        template<class T>
        class Matrix {
        public:
                // Стратегия заполнения матрицы значениями.
                class FillStrategy {
                public:
                        virtual T getItemBy(int row, int column) throw(OperationFailed) = 0;
                };
        private:
                friend Matrix<T> operator*<T>(const Matrix<T> &, const Matrix<T> &);
                int _rows, _columns;
                T *_ptr_items;
                int _size() const {
                        return _rows * _columns;
                }
                int _index(int row, int column) const throw(InvalidArgument) {
                        if(row <= 0 || row > _rows || column <= 0 || column > _columns)
                                throw InvalidArgument();
                        return (row - 1) * _columns + (column - 1);
                }
                void _init(int rows, int columns) throw(InvalidArgument) {
                        if(rows <= 0 || columns <= 0)
                                throw InvalidArgument();
                        _rows = rows;
                        _columns = columns;
                        _ptr_items = new T[_size()];
                }
                Matrix(int rows, int columns) throw(InvalidArgument) {
                        _init(rows, columns);
                }
        public:
                Matrix(int rows, int columns, FillStrategy &defaultsGenerator) throw(InvalidArgument, OperationFailed) {
                        _init(rows, columns);
                        setItems(defaultsGenerator);
                }
                Matrix(const Matrix &other) {
                        _rows = other._rows;
                        _columns = other._columns;
                        memcpy(_ptr_items, other._ptr_items, _size() * sizeof(T));
                }
                virtual ~Matrix() {
                        delete _ptr_items;
                }
                int getRows() const {
                        return _rows;
                }
                int getColumns() const {
                        return _columns;
                }
                T getItem(int row, int column) const throw(InvalidArgument) {
                        return _ptr_items[_index(row, column)];
                }
                void setItem(int row, int column, T value) throw(InvalidArgument) {
                        _ptr_items[_index(row, column)] = value;
                }
                void setItems(FillStrategy &generator) throw(OperationFailed) {
                        for(int row = 1; row <= _rows; ++row)
                                for(int column = 1; column <= _columns; ++column)
                                        setItem(row, column, generator.getItemBy(row, column));
                }
        };

        // Вектор - это матрица-строка или матрица-столбец.
        template<class T>
        class Vector: public Matrix<T> {
        public:
                enum Orientation {
                        ROW, COLUMN
                };
        private:
                Orientation _orientation;
                int _getRows(int size, Orientation orientation) const {
                        switch(orientation) {
                        case ROW:
                                return 1;
                        case COLUMN:
                                return size;
                        default:
                                throw InternalError();
                        }
                }
                int _getColumns(int size, Orientation orientation) const {
                        switch(orientation) {
                        case ROW:
                                return size;
                        case COLUMN:
                                return 1;
                        default:
                                throw InternalError();
                        }
                }
        public:
                Vector(int size, typename Matrix<T>::FillStrategy &defaultsGenerator, Orientation orientation) throw(InvalidArgument, OperationFailed, InternalError):
                                Matrix<T>(_getRows(size, orientation), _getColumns(size, orientation), defaultsGenerator),
                                _orientation(orientation) {
                }
                int getSize() const throw(InternalError) {
                        switch(_orientation) {
                        case ROW:
                                return Matrix<T>::getColumns();
                        case COLUMN:
                                return Matrix<T>::getRows();
                        default:
                                throw InternalError();
                        }
                }
                T getItem(int index) const throw(InvalidArgument, InternalError) {
                        switch(_orientation) {
                        case ROW:
                                return Matrix<T>::getItem(1, index);
                        case COLUMN:
                                return Matrix<T>::getItem(index, 1);
                        default:
                                throw InternalError();
                        }
                }
                void setItem(int index, T value) throw(InvalidArgument, InternalError) {
                        switch(_orientation) {
                        case ROW:
                                Matrix<T>::setItem(1, index, value);
                                break;
                        case COLUMN:
                                Matrix<T>::setItem(index, 1, value);
                                break;
                        default:
                                throw InternalError();
                        }
                }
        };
}

// ПРИМЕРЫ ПРИМЕНЕНИЯ.

using namespace matrix;

// Матрица целых чисел.
typedef Matrix<int> MyMatrix;
// Вектор целых чисел.
typedef Vector<int> MyVector;

// Стратегии заполнения матриц значениями.
namespace strategyusing
{
        // Заполнение значением по умолчанию.
        class MyDefaultsGenerator: public MyMatrix::FillStrategy {
        public:
                virtual int getItemBy(int row, int column) throw(OperationFailed) {
                        return 0;
                }
        };

        // Ввод значений пользователем.
        class MyUserValuesGenerator: public MyMatrix::FillStrategy {
        public:
                virtual int getItemBy(int row, int column) throw(OperationFailed) {
                        cout << "В позиции (" << row << ", " << column << ")? ";
                        int value;
                        cin >> value;
                        return value;
                }      
        };

        // Операция транспонирования матрицы.
        class MyTransposition : public MyMatrix::FillStrategy {
                MyMatrix &_source;
        public:
                MyTransposition(MyMatrix &source):
                                _source(source) {
                }
                virtual int getItemBy(int row, int column) throw(OperationFailed) {
                        try {
                                return _source.getItem(column, row);
                        } catch(InvalidArgument) {
                                throw OperationFailed();
                        }
                }              
        };
}

using namespace strategyusing;

// Вывод матрицы на экран.
template<class T>
void printMatrix(const Matrix<T> &m) {
        for(int i = 1; i <= m.getRows(); ++i) {
                for(int j = 1; j <= m.getColumns(); ++j)
                        cout << m.getItem(i, j) << " ";
                cout << endl;
        }
}

int main() {
        try {
                MyDefaultsGenerator defaultsGenerator;
                MyUserValuesGenerator userValuesGenerator;

                cout << "Матрица размера 2 на 2" << endl;
                MyMatrix a(2, 2, userValuesGenerator);
                printMatrix<int>(a);


                cout << "умножается на вектор" << endl;
                MyVector b(2, defaultsGenerator, MyVector::COLUMN);
                b.setItem(1, 5);
                b.setItem(2, 6);
                printMatrix<int>(b);

                MyMatrix c = a * b;
                cout << "результат" << endl;
                printMatrix<int>(c);

                cout << "Вектор" << endl;
                MyVector d(2, defaultsGenerator, MyVector::ROW);
                d.setItem(1, 5);
                d.setItem(2, 6);
                printMatrix<int>(d);

                MyTransposition transposition(a);

                cout << "умножается на матрицу" << endl;
                MyMatrix e(2, 2, transposition);
                printMatrix<int>(e);

                Matrix<int> f = d * e;
                cout << "результат" << endl;
                printMatrix<int>(f);

        } catch(InvalidArgument) {
                cout << "ОШИБКА ПРОГРАММИРОВАНИЯ" << endl;
        } catch(InternalError) {
                cout << "ОШИБКА ПРОГРАММИРОВАНИЯ" << endl;
        }
        return 0;
}
Так как количество классов быстро растёт, то для удобства отделения "зёрен от плевел" ввёл пространства имён.

Для демонстрации возможностей подхода сделал три разных генератора, решающих разные задачи.
« Последнее редактирование: 14-02-2008 19:05 от dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Люсь
Команда клуба

ru
Offline Offline
Пол: Женский

« Ответ #24 : 15-02-2008 04:20 » 

охохохохо...

спасибо вам всем, прогу сдала Улыбаюсь
кто-то был прав насчёт формата выходных данных - это должен был быть вектор Улыбаюсь
переделывала у него на глазах, попутно ещё кое-что подправила Улыбаюсь

Код:
#include <iostream>
#include <fstream>
using namespace std;

class vector{ public: int el[3];};
class matrica{
public:
    int el[3][3];
    vector operator*(vector& vec)
    {
        vector res;
        vector prom;
        for (int i=0; i<=2; i++)
        {
            res.el[i]=0;
            for (int j=0; j<=2; j++)
            {
               prom.el[j] = el[i][j] * vec.el[j];
               res.el[i] += prom.el[j];
            }
        }
        return res;
    };
};

void main()
{
    vector vec;
    matrica matr;
    vector res;

    ifstream mfs("matrica.txt", ios::in);
    ifstream vfs("vector.txt", ios::in);
    ofstream rfs("result.txt", ios::out);

    int i, j;
    for (i=0; i<=2; i++)
    {
        vfs >> vec.el[i];
        for (j=0; j<=2; j++)
        {
            mfs >> matr.el[i][j] ;
        }
    }

    // matrica * vector
   
    res = matr * vec;

    for (j=0; j<=2; j++)
    {
       rfs << res.el[j] << endl;
       cout << res.el[j] << endl ;
    }

    mfs.close();
    vfs.close();
    rfs.close();
    return;
}

щас теорию почитаю - пойду теоретическую часть сдавать Улыбаюсь

А насчёт всех остальных замечаний - вы только погодите, дайте вернуться за свой комп - буду спрашивать много и нудно, разбирая ваши хитроумности по косточкам Улыбаюсь

Джон, спасибо!
Записан

Посторонним просьба не беспокоить!
-------------------------------------------------
O (I) Rh +
Люсь
Команда клуба

ru
Offline Offline
Пол: Женский

« Ответ #25 : 15-02-2008 04:28 » 

Прикольно Улыбаюсь))

Полезла в инет искать ответ на конкретный вопрос - первая же ссылка - переписка нас с вами Улыбаюсь))))
http://www.yandex.ru/yandsearch?text=%D0%BE%D1%82%D0%BB%D0%B8%D1%87%D0%B8%D0%B5+%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D1%8B+%D0%BE%D1%82+%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B0

https://forum.shelek.ru/index.php?action=printpage;topic=12347.0

Я вас люблю!!!
Записан

Посторонним просьба не беспокоить!
-------------------------------------------------
O (I) Rh +
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #26 : 15-02-2008 04:39 » 

Люськин, молоток! Так держать!! Улыбаюсь
Записан

Люсь
Команда клуба

ru
Offline Offline
Пол: Женский

« Ответ #27 : 16-06-2009 15:24 » 

А вот фиг я вам вернулась за свой комп и спрашивала долго и нудно... Случилось это только через полтора года - просто петух жаренный клюнул, надо сделать 3 курсовые работы за 4 месяца ))
Записан

Посторонним просьба не беспокоить!
-------------------------------------------------
O (I) Rh +
McZim
Команда клуба

ru
Offline Offline
Пол: Мужской
Я странный


WWW
« Ответ #28 : 16-06-2009 20:27 » 

Люсь, давай поможем!
Записан

The CBO without stats is like a morning without coffee. (c) T.Kyte.
Люсь
Команда клуба

ru
Offline Offline
Пол: Женский

« Ответ #29 : 17-06-2009 03:25 » 

Ага Улыбаюсь Погоди тока, с мыслями соберусь...
Записан

Посторонним просьба не беспокоить!
-------------------------------------------------
O (I) Rh +
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines