Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Двумерные массивы на С++

8.3K
03 октября 2006 года
Chuvak
40 / / 23.11.2005
Есть класс, елементом данных которого является динамический массив
(матрица), как объявить operator[], чтобы он принимал два параметра и
возвращал нужный елемент?

P.S. operator[] (int,int) не катит - ... must have one parameter...
Страницы:
9
03 октября 2006 года
Lerkin
3.0K / / 25.03.2003
А принципиально использовать []?

Я делал через (), и было это так:
Код:
class matrix_t
{
    union
    {
    float p[16];
    float e[4][4];
    };

...
    float &operator ()(const int i, const int j)
    {
    return e[j];
    }

    float operator ()(const int i, const int j) const
    {
    return e[j];
    }
...
}
1.9K
03 октября 2006 года
[*]Frosty
278 / / 17.06.2006
При перегрузке оператора Вы не можете менять колическво параметров).
9
03 октября 2006 года
Lerkin
3.0K / / 25.03.2003
[QUOTE='
  • Frosty']При перегрузке оператора Вы не можете менять колическво параметров).[/QUOTE]

    Абсолютно справедливо. Жалко только, что красивая идея [i, j] переходит в банальное [j]... :)
  • 1.8K
    03 октября 2006 года
    k3Eahn
    365 / / 19.12.2005
    [quote=Lerkin]Абсолютно справедливо. Жалко только, что красивая идея [i, j] переходит в банальное [j]... :)[/quote]
    оператор запятая может быть перегружен;)
    309
    04 октября 2006 года
    el scorpio
    1.1K / / 19.09.2006
    Использование оператора () просто, но стилистически неверно - объект начинает выглядеть как функция.
    Но можно сделать так, что array [j] будет реализован как array.operator[] (i).operator[] (j)

    Двумерный массив можно реализовать двумя способами:
    1. Массив массивов - объект возвращает ссылку на другой объект, который также может трактоваться как массив.

    2. Создавать временный объект с оператором [] (int Second_Index), который будет вызывать функцию чтения значения основного объекта. Я пробовал это сделать - получилось, но было использовано столько дополнительных команд :eek:
    1.8K
    04 октября 2006 года
    k3Eahn
    365 / / 19.12.2005
    Продолжая тему перегрузки оператора запятая:
    Код:
    template <typename T>
    class array2d
    {
     
    public:
     
     template<class T1,class T2>
     T operator[](const std::pair<T1,T2>& p)
     {
      std::cout<<"first="<<p.first<<" second="<<p.second<<std::endl;
      return (T)0;
     };
     
    };
     
    template <typename T>
    struct index
    {
     
     template <typename T2>
     std::pair<T,T2> operator,(const T2& j)
     {
      return std::make_pair(val,j);
     };
     
     operator T() const
     {
      return val;
     };
     
     index(T _val) : val(_val) {};
     
    private:
     
     T val;
    };
     
     
    int _tmain(int argc, _TCHAR* argv[])
    {
     array2d<float> array;
     index<int> a=654;
     index<bool> b=true;
     index<int> c=a;
     array[a,b];
     array[a,890];
     array[a,c];
     std::cin.get();
     return 0;
    }
    350
    04 октября 2006 года
    cheburator
    589 / / 01.06.2006
    Оператор [] перегрузить таким образом, чтобы он принимал в качестве параметра точку двумерного пространства. Для этой цели можно объявить специальную структуру или класс, а можно просто воспользоваться вектором (имеется в виду вектор в физико-математическом смысле). Вектор описывается с помощью std::vector, размерность которого можно проверять в самом операторе [].
    Код:
    class MyClass
    {
    ...
      MyType operator [] (const std::vector<int> &point)
      {
        if (point.size() != 2)
        {
          // Генерировать исключение
        }
        // Вернуть требуемый элемент
      }
    ...
    }
    309
    05 октября 2006 года
    el scorpio
    1.1K / / 19.09.2006
    [QUOTE=cheburator]Оператор [] перегрузить таким образом, чтобы он принимал в качестве параметра точку двумерного пространства. Для этой цели можно объявить специальную структуру или класс[/QUOTE]
    И как, позволю себе спросить, это будет выглядеть :) ?
     
    Код:
    Item = Array [TIndex (x, y)];

    Довольно таки неуклюже, но иначе не получится :(

    Тогда уж лучше вместо переопределения использовать именованые методы константного и изменяемого чтения
     
    Код:
    TMyArray
    {
    private:
    // ......
    public:
    TItem& Items (int Index1, int Index2); // Чтение элемента для изменения
    const TItem& Items (int Index1, int Index2) const; // Чтение константного элемента
    // .....
    };

    Согласен, несколько отличается от исходных условий задачи, зато дёшево, надёжно и практично :D
    3
    05 октября 2006 года
    Green
    4.8K / / 20.01.2000
    А мне кто-нибудь может объяснить, чем не подходит С++ формат [j] и чем лучше и красивее в данном случае паскаль-формат [i,j] ?

    Другими славами: стоит ли проблема выеденного яйца?
    IMHO нет, более того, подобное смешение стилей в последствии может выйти боком.

    Класс-матрица, о котором говорит автор, это (пусть в простейшем случае) vector< vector<ElementType> >. Т.о. можно вообще не заморачиваться со специальным классом.

    Если дойдет до необходимости замены vector<vector> на спец.класс, созданный собственоручно или взятый из готовых мат.библиотек, то это произойдет просто и безболезнено, если изначально придерживаться концепции языка С++: индексация многомерных массивов выглядит как [j].

    P.S. Для любителей паскаля можно ввести макросы:
    #define BEGIN {
    #define END }
    309
    05 октября 2006 года
    el scorpio
    1.1K / / 19.09.2006
    Цитата:

    А мне кто-нибудь может объяснить, чем не подходит С++ формат [j] и чем лучше и красивее в данном случае паскаль-формат [i,j] ?


    Я могу - C++ не позволяет объявить метод объекта operator [] (int x, int y) :D. Компилятор говорит, что [] должен иметь только один параметр :(. Что есть большой недостаток.
    Вот и приходится бедным людям, которые хотят, чтобы их объект выглядел как двухмерный массив, затылки чесать....

    Сам я, в своё время, придумал что-то подобное этому

    Код:
    class TD2Array
    {[INDENT]class TItem
    {
    friend TD2Array; // Объявляем "другом" для доступа к закрытым функциям
    private:[INDENT]TD2Array *pArray;
    int First;
    [/INDENT]public:[INDENT]TItem (TD2Array *Owner, int Index): pArray (Owner), First (Index)
         {} // Конструктор временного объекта
    TResult& operator[] (int Index) // Второй оператор индексации
         {return pArray->Read_Item (First, Index);}
    [/INDENT]};
    [/INDENT]private:
         TResult& Read_Item (int First, int Second); //Закрытая функция чтения результата
    public:
         TItem operator[] (int Index) // Первый оператор индексации
               {return TItem (this, Index);} // Возвращаем объект для обработки второго оператора индексации
    };

    При наличии стольких промежуточный За скорость работы программы вполне предсказуема :)

    P.S.
    За мелкие погрешности прошу сильно не пинать - пишу по памяти :)
    3
    05 октября 2006 года
    Green
    4.8K / / 20.01.2000
    Объяснение не принимается... :)

    Как будет выглядеть алгоритм при записи [i,j] ?
    Не так ли:
    1) находим i-ю строку;
    2) выбираем из неё j-й элемент.

    Как будет работать алгоритм при записи [j]:
    1) возвращаем i-б строку;
    2) возвращаем из неё j-й элемент.

    Не вижу изменения в сложности (количестве операций) между двумя вариантами.

    Почему бы для твоего примера не сделать так:
    Код:
    class TD2Array
    {
    public:

        class TLine
        {
        public:
            TResult& operator[] (int Index); // Второй оператор индексации
        };

        TLine& operator[] (int Index) // Первый оператор индексации
    };
    8.3K
    05 октября 2006 года
    Chuvak
    40 / / 23.11.2005
    Извиняюсь, я устатый был, недодумал немного :)
    Не учел того, что если operator[] вернет (Item *), то к нему можно
    применить стандартный [], получится то, что надо: matrix[j]; :)
    А вышеизложенные идеи интересные, но нет времени на их реализацию.
    8.3K
    05 октября 2006 года
    Chuvak
    40 / / 23.11.2005
    [QUOTE=Green]
    Класс-матрица, о котором говорит автор, это (пусть в простейшем случае) vector< vector<ElementType> >. Т.о. можно вообще не заморачиваться со специальным классом.[/QUOTE]
    Класс должен определять математические ф-ции матрицы.

    Цитата:

    P.S. Для любителей паскаля можно ввести макросы:
    #define BEGIN {
    #define END }


    Я паскаль не изучал, только сейчас в универе азы учу. Отсюда следуюций вопрос:
    Нельзя ли подобным образом заменить паскалевские begin на родное '}' ?
    И долбаные одинарные кавычки двойными? :) :) :)

    309
    06 октября 2006 года
    el scorpio
    1.1K / / 19.09.2006
    [QUOTE=Green]Объяснение не принимается[/QUOTE]
    Почему? :)

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

    Хотя ограничение оператора индексации одним параметром - большой недостаток C++.
    3
    06 октября 2006 года
    Green
    4.8K / / 20.01.2000
    [QUOTE=el scorpio]
    Хотя ограничение оператора индексации одним параметром - большой недостаток C++.[/QUOTE]
    IMHO это не недостаток, а наоборот, некая стандартизация, приведение к единому интерфейсу. И я описал это уже чуть выше по теме.

    Удобно, конечно, было бы если напряжение в электросети было бы таким, как нужно большинству приборов, но пусть уж лучше будет везде одинаковым - 220В. :)
    350
    09 октября 2006 года
    cheburator
    589 / / 01.06.2006
    [QUOTE=Green]Почему бы для твоего примера не сделать так:
    Код:
    class TD2Array
    {
    public:

        class TLine
        {
        public:
            TResult& operator[] (int Index); // Второй оператор индексации
        };

        TLine& operator[] (int Index) // Первый оператор индексации
    };
    [/QUOTE]
    Вынужден признать, у стандартного С++-подхода есть свои недостатки.
    1. При получении ij-го элемента матрицы мы должны получать именно элемент непосредственно. Почему это должно выглядеть как получение j-го элемента i-й строки? Почему тогда не i-го элемента j-го столбца?
    2. Ладно. Фиг с ним. Получаем мы элемент через строку. Т. е. мы можем обратиться одним оператором индексации и получить всю строку как объект.
    А столбец?

    Лично я считаю, что в определенных математических задачах "естественнее" и логичнее применить, скажем, такой подход.
    1. Оператор [] выбирает непосредственно элемент матрицы и потому в качестве параметра берет пару чисел. В общем (не матричном) случае - n-мерный или даже произвольномерный вектор (к примеру, если представить в виде класса n-мерное пространство).
    2. Оператором [] нелогично получать строки и столбцы матрицы. Предположим, мы перегрузили оператор [] с параметром int. Что он будет возвращать - столбец или строку?
    Лучше сделать:
    2A. Методы типа RowVector& row (int) и ColumnVector& column (int), которые вернут вектор-строку и вектор-столбец соответственно (в крайнем случае, опять же матрицу, содержащую соответственно одну строку или один столбец - но в таком случае придётся для получения элемента такой матрицы явно указывать единицу в параметре оператора [], а если создать специализированные объекты - вектор-строки и вектор-столбцы - для них можно перегрузить оператор [] с параметром просто int). Термины "вектор-строка" и "вектор-столбец" здесь употреблены в математическом смысле. Кто не понимает их - обращайтесь к соответствующей литературе :)
    2B. Методы, возвращающие коллекцию (в терминологии С++ - контейнер) строк и столбцов, к которой уже можно обратиться оператором [] для получения конкретной строки или столбца.
    Считаю, что 2А подходит больше, т. к. в математике нет такого понятия, как "коллекция строк" :) и незачем "портить" красивый математический интерфейс "непонятными" методами и дополнительными классами.
    3
    09 октября 2006 года
    Green
    4.8K / / 20.01.2000
    Это не недостаток С++, а недостаток структуры памяти современных ЦЭВМ,-она линейна, а сл-но n-мерные массивы эмулируются набором одномерных.
    309
    09 октября 2006 года
    el scorpio
    1.1K / / 19.09.2006
    cheburator.
    В C++ не существует реализации такого понятия, как многомерный массив.
    Всё, что мы называем "многомерными" массивам - это либо указатели n-го порядка (указатель на указатель на объект в памяти), индексируемые на каждом этапе обращения по адресу, либо линейные массивы, индексируемые по следующей формуле "i1*s2+i2".
    А для реализации "строк" и "столбцов" можно написать свой класс, который будет иметь подобные свойства, наподобие Cols и Rows в TStringGrid.
    5.4K
    09 октября 2006 года
    Svyatozar
    221 / / 11.09.2006
    [QUOTE=Chuvak]Класс должен определять математические ф-ции матрицы.[/QUOTE]
    Называется Matrix Template Library, MTL http://osl.iu.edu/research/mtl/
    2.9K
    09 октября 2006 года
    Ation
    96 / / 27.07.2004
    а если попробовать анонимные экземпляры? Что-то типа

    class Index{
    friend operator[] (const Index);
    protected:
    int i; int j;
    public:
    Index(in_i,in_j):i(in_i),j()in_j{}
    }

    float& operator [] (const Index index)
    {
    return ...;
    }

    //gdeto tam
    FloatMas[Index(1,2)]=FloatMas[Index(1,1)];
    309
    10 октября 2006 года
    el scorpio
    1.1K / / 19.09.2006
    Ation
    Извращение :) . Кроме того, не соответствует условию задачи - создать объект, который будет иметь интерфейс двухмерного массива ("Array[x][y]") :(
    А если "думать иначе", то проще сразу объявить свойство с двойной индексацией - реализуется без всяких "временных" объектов.
    21K
    11 октября 2006 года
    Nuller_
    6 / / 06.10.2006
    если твой динамический массив относится к POD-типам (int,float,char и т.д.), то можно сделать следующий оператор[]

     
    Код:
    int* CMatrix::operator[] (int i)
    {
    // w- ширина матрицы
    // **table - таблица коэффициентов матрицы
         return (i < 0 || i >= w) ? NULL : table;  

    }

    то есть в результате действия оператора[] возвращается i-я строка матрицы. Ну а так как она представляет собой массив int-овый, значит к ней в свою очередь применим оператор[].

    m[j] (m - объект класса matrix)
    раскрывается в
    (m.operator[](i)) [j];
    21K
    11 октября 2006 года
    Nuller_
    6 / / 06.10.2006
    вот небольшой примерчик (рабочий)
    Код:
    // matrix.h

    #include <memory.h>
    #include <iostream>
    #include <cstdio>
    using namespace std;

    class matrix
    {
        int  **mas;     // собственно таблица
        int  w, h;  // ширина и высота
       
    public:
        matrix (int,int);
        ~matrix();

        int* operator[] (int);
        void show();
    };

    matrix::matrix(int _w, int _h) : w(_w), h(_h)
    {
        mas = new int*[w];
        for(int i=0; i<w; ++i)
        {
            mas = new int[h];
            memset( mas, 0, h * sizeof(int) );
        }
    }

    matrix::~matrix()
    {
        for(int i=0; i<w; ++i)
            delete [] mas;
        delete [] mas;
    }

    int* matrix::operator[] (int i)
    {
         return (i < 0 || i >= w) ? NULL : mas;
    }


    void matrix::show() // демонстрационный вывод на экран
    {
        cout << endl;
        for(int j=0; j<h; ++j)
        {
            for(int i=0; i<w; ++i)
            {
                cout << mas[j] << " ";
            }
            cout << endl;
        }
    }


    Код:
    // main.cpp

    #include "matrix.h"

    void main()
    {
        matrix m(3,4);   // матрица 3х4
        m.show();

        m[0][1] = 1;
        m[1][2] = 3;
        m[2][3] = 5;
        m.show();
    }


    нюанс: в этом примере проверка границ (bound-check) как таковая отсутствует! То есть, если написать m[10][100] = 1000, то программа рухнет ;)
    309
    11 октября 2006 года
    el scorpio
    1.1K / / 19.09.2006
    [QUOTE=Nuller_]в этом примере проверка границ (bound-check) как таковая отсутствует! То есть, если написать m[10][100] = 1000, то программа рухнет ;)[/QUOTE]
    Верно мыслите :)
    Если писать объект "многомерный массив", то он сам должен проверять допустимость индексации для каждой размерности.
    350
    11 октября 2006 года
    cheburator
    589 / / 01.06.2006
    [QUOTE=Green]Это не недостаток С++, а недостаток структуры памяти современных ЦЭВМ,-она линейна, а сл-но n-мерные массивы эмулируются набором одномерных.[/QUOTE]
    А то, что нельзя перегрузить оператор [] с несколькими параметрами - чей недостаток?
    А эмуляция многомерных массивов одномерными какое имеет отношение к интерфейсу класса?
    С чего бы оператор [] обязательно должен иметь дело с массивом?
    3
    11 октября 2006 года
    Green
    4.8K / / 20.01.2000
    А что молотком сложно шурупы закручивать, чей недостаток: молотка или шурупа?
    2.9K
    11 октября 2006 года
    Ation
    96 / / 27.07.2004
    el scorpio
    На самом деле спрашивалось, как перегрузить оператор [] так, чтоб он принимал два параметра. Согласно спецификации языка - никак. Единственный способ так извращатся. А возвращение ссылки на объект соответствующий переданому индексу сосздает "впечатление" работы с массивом.
    Тогда как
    int* CMatrix::operator[] (int i)
    потенциально опасно
    при вызове
    matrix m(3,4);
    m[10][1]=5;
    ксласс проверит и послушно вернет NULL для m5[5], а далее последует обращение к адресу (NULL+sizeof(int))
    что будет дальше, думаю, объяснять не надо :)
    309
    12 октября 2006 года
    el scorpio
    1.1K / / 19.09.2006
    [QUOTE=cheburator]А эмуляция многомерных массивов одномерными какое имеет отношение к интерфейсу класса?
    С чего бы оператор [] обязательно должен иметь дело с массивом?[/QUOTE]
    Конечно же, реализация данных внутри класса может быть любой. Просто здесь действует одно из основных правил синтаксиса - реализация должна соответствовать описанию.

    ation
    На самом деле, для объекта-массива matrix m(3,4) использование "m[10][1]=5" безопасно - просто хороший класс выдаст ERangeError :)
    Куда хуже будет "m[1][10]=5" - проверка индексации у второго оператора отсутствует, посему значение запишется в случайную область памяти, которая, по закону Мерфи, будет занята архиважными для программы данными :D
    2.9K
    12 октября 2006 года
    Ation
    96 / / 27.07.2004
    Тов el_scorpio.
    Хороший класс в данной ветке не появлялся. Если планировать с умом, то возвращение указателя неприемлимо как таково. Поэтому лучше реализовать одномернывй массив. Например
    template <class T>
    class Massive
    {
    private: T* mas;
    ...
    T& operator [] (const int index) {//проверка
    return mas[index]; }
    }

    main()
    {
    Massive<Massive<int>> m(10);
    //установка размеров
    m[n][z]=m[z][n];
    }

    полностью заменяет двухмерный массив. Немножко уродливая инициализация полностью оправдывается интерфесом доступа к ячейкам, идентичным двумерному массиву.
    Вот только не вижу смысла в замене стандартных средств массивов.
    309
    13 октября 2006 года
    el scorpio
    1.1K / / 19.09.2006
    Ation
    Собственно говоря, здесь можно просто использовать стандартный шаблон DynamicArray из Builer'а.
    И конструкции типа "DynamicArray <DynamicArray <TMyStruct>>" мне использовать приходилось не раз.
    Так что "америку" никто не открыл :)
    350
    13 октября 2006 года
    cheburator
    589 / / 01.06.2006
    [QUOTE=Green]А что молотком сложно шурупы закручивать, чей недостаток: молотка или шурупа?[/QUOTE]
    Молоток для этого не предназначен. Выходит, С++ не предназначен для математических задач?
    3
    13 октября 2006 года
    Green
    4.8K / / 20.01.2000
    [QUOTE=cheburator]Молоток для этого не предназначен. Выходит, С++ не предназначен для математических задач?[/QUOTE]
    А кто сказал, что молоток в метафоре это C++ ?
    Вроде бы про оператор [] говорили.

    У тебя не возникает вопроса: почему в С++ нельзя определить оператор + восемью параметрами? :)
    3
    13 октября 2006 года
    Green
    4.8K / / 20.01.2000
    [QUOTE=cheburator]Молоток для этого не предназначен. Выходит, С++ не предназначен для математических задач?[/QUOTE]
    А кто сказал, что молоток в метафоре это C++ ?
    Вроде бы про оператор [] говорили.

    У тебя не возникает вопроса: почему в С++ нельзя определить оператор + восемью параметрами? :)
    Или оператор -> десятью параметрами?
    2.9K
    13 октября 2006 года
    Ation
    96 / / 27.07.2004
    [QUOTE=el scorpio]
    Собственно говоря, здесь можно просто использовать стандартный шаблон DynamicArray из Builer'а.
    И конструкции типа "DynamicArray <DynamicArray <TMyStruct>>" мне использовать приходилось не раз.
    Так что "америку" никто не открыл :)[/QUOTE]
    А кто говорит что нельзя? :)
    Только вот код становится зависим от компилятора. Лучше СТЛ.
    309
    14 октября 2006 года
    el scorpio
    1.1K / / 19.09.2006
    [QUOTE=Ation]А кто говорит что нельзя? :)
    Только вот код становится зависим от компилятора. Лучше СТЛ.[/QUOTE]
    А разве бывают "независимые" коды :)?
    Кто-то пишет программы, используя MFC, другие эксплуатируют VCL...
    А DynamicArray можно переписать при особом желании либо для "независимости", или же изучения языка ради (что, собственно я как-то и сделал :D )
    3
    14 октября 2006 года
    Green
    4.8K / / 20.01.2000
    [QUOTE=el scorpio]А разве бывают "независимые" коды :)?
    [/QUOTE]
    А почему бы нет?
    [QUOTE=el scorpio]
    Кто-то пишет программы, используя MFC, другие эксплуатируют VCL...
    [/QUOTE]
    Только вот бизнес-логика в большинстве своем не зависит от оконных библиотек.
    2.9K
    14 октября 2006 года
    Ation
    96 / / 27.07.2004
    Пошел флейм :)))
    Вернемся к баранам...
    А что если перегрузить оператор (). И представить, что это [] ;)
    только вот обращение к элементу типа
    SomeName m;
    m(5,4)=3;
    окажет сильное влияние на ум увидевшего, вплоть до полного перехода на бейсик )
    309
    16 октября 2006 года
    el scorpio
    1.1K / / 19.09.2006
    [QUOTE=Ation]
    А что если перегрузить оператор (). И представить, что это [] ;)
    только вот обращение к элементу типа
    SomeName m;
    m(5,4)=3;
    [/QUOTE]
    А потом, через пол-года, открыть старые исходники и долго ломать голову, откуда это за функция и что она делаеть :D
    350
    16 октября 2006 года
    cheburator
    589 / / 01.06.2006
    [QUOTE=Green]А кто сказал, что молоток в метафоре это C++ ?
    Вроде бы про оператор [] говорили.

    У тебя не возникает вопроса: почему в С++ нельзя определить оператор + восемью параметрами? :)[/QUOTE]
    Нет. Сложение - по определению двухместная операция.
    350
    16 октября 2006 года
    cheburator
    589 / / 01.06.2006
    [QUOTE=Ation]Пошел флейм :)))
    Вернемся к баранам...
    А что если перегрузить оператор (). И представить, что это [] ;)
    только вот обращение к элементу типа
    SomeName m;
    m(5,4)=3;
    окажет сильное влияние на ум увидевшего, вплоть до полного перехода на бейсик )[/QUOTE]
    А шо, неплохая идея, только выглядеть будет действительно немного путано
    Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
    Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог