Avatar billede gulbaek Nybegynder
07. november 2006 - 14:56 Der er 9 kommentarer og
1 løsning

2D Array med proxy klasse

Hejsa

Har en 2D Table class, som umiddelbart virker fint nok. Dog er jeg ikke helt tilfreds med den måde jeg tildeler Table en ny værdi.

minTable(1,1) = 23;  Ønsker at det skal foregå på følgende måde.
minTable[1][1] = 23; Og har fundet frem til at det skulle være muligt, hvis man benytter sig af en proxy klasse.

Har fundet følgende eksempel.
template<class T>
class Array2D {
public:
  class Array1D {
  public:
  T& operator[](int index);
  const T& operator[](int index)const;
  ...
};
Array1D operator[](int index);
const Array1D operator[](int index)const;
...
};

Så skulle det være muligt. Håber nogen kan hjælpe mig med at få det overført til min egen kode, da jeg ikke lige umiddelbart kan få det til at virke selv.

//Table.h
#ifndef TABLE_H
#define TABLE_H

template <typename T>
class Table
{
public:
    Table();
    Table(int m, int n);
    Table(int m, int n, const T& value);
    Table(const Table<T>& rhs);
    ~Table();

    Table<T>&    operator=(const Table& rhs);
    T&            operator()(int i , int j);


    int numRows()const;
    int numCols()const;

    void resize(int m, int n);
    void resize(int m, int n, const T& value);
private:
    void destroy();
private:
    int mNumRows;
    int mNumCols;
    T** mDataMatrix;
};

template <typename T>
Table<T>::Table<T>()
{
    mDataMatrix = 0;
    mNumRows    = 0;
    mNumCols    = 0;
}

template <typename T>
Table<T>::Table<T>(int m, int n)
{
    mDataMatrix    = 0;
    mNumRows    = 0;
    mNumCols    = 0;
    resize(m, n, T());
}

template <typename T>
Table<T>::Table<T>(int m, int n, const T &value)
{
    mDataMatrix    = 0;
    mNumRows    = 0;
    mNumCols    = 0;
    resize(m, n, value);
}

template <typename T>
Table<T>::Table<T>(const Table<T> &rhs)
{
    mDataMatrix    = 0;
    mNumRows    = 0;
    mNumCols    = 0;
    *this        = rhs;
}

template <typename T>
Table<T>::~Table<T>()
{
    destroy();
}

template <typename T>
Table<T>& Table<T>::operator =(const Table& rhs)
{
    //Check for self assignment.
    if(this = &rhs) return *this;

    //Reallocate the table based on rhs info.
    resize(rhs.mNumRows, rhs.mNumCols);

    //Copy the entries over element-by-element.
    for(int i = 0; i < mNumRows; ++i)
        for(int j = 0; j < mNumCols; ++j)
            mDataMatrix[i][j] = rhs.mDataMatrix[i][j];

    //return a reference to *this so we can do chain
    //assignments: x = y = z = w = ...
    return *this;
}

template <typename T>
T& Table<T>::operator ()(int i, int j)
{
    return mDataMatrix[i][j]; //return the ijth table entry.
}

template <typename T>
int Table<T>::numRows() const
{
    return mNumRows;
}

template <typename T>
int Table<T>::numCols() const
{
    return mNumCols;
}

template <typename T>
void Table<T>::resize(int m, int n)
{
    //Call resize and use default constructor T() as 'value'
    resize(m, n, T());
}

template <typename T>
void Table<T>::resize(int m, int n, const T &value)
{
    //Destroy
    destroy();

    // Save dimensions.
    mNumRows = m;
    mNumCols = n;

    //Allocate a row (array) of pointers.
    mDataMatrix = new T*[mNumRows];

    //Now loop through each pointer in this row array.
    for(int i = 0; i < mNumRows; ++i)
    {
        //And allocate a column (array) to build the table.
        mDataMatrix[i] = new T[mNumCols];

        //now loop through each element in this row[i]
        //and copy 'value' into it.
        for(int j = 0; j < mNumCols; ++j)
            mDataMatrix[i][j] = value;
    }
}

template <typename T>
void Table<T>::destroy()
{
    //Does the matrix exists?
    if(mDataMatrix)
    {
        for(int i = 0; i < mNumRows; ++i)
        {
            //does the ith row exist?
            if(mDataMatrix[i])
            {
                //Yes, delete it.
                delete[]mDataMatrix[i];
                mDataMatrix[i] = 0;
            }
        }
        //Delete the row array.
        delete[] mDataMatrix;
        mDataMatrix = 0;
    }
    mNumRows = 0;
    mNumCols = 0;
}

#endif //TABLE_H



//Main.cpp
#include "Table.h"
#include <iostream>
using namespace std;

int main()
{
    Table<int> minTable(2,2);

    minTable(1,1) = 23;

    cout << davs(1,1) << endl;
}
Avatar billede lars314 Nybegynder
07. november 2006 - 15:13 #1
Dette er ikke et svar på dit spørgsmål, men du bør læse følgende:

Why shouldn't my Matrix class's interface look like an array-of-array?

http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.11
Avatar billede gulbaek Nybegynder
07. november 2006 - 15:31 #2
Takker for linket, men blev nu ikke helt overbevist til at droppe det :-)

Men er af den overbevisning at det er nemmere at læse
minTable[1][1] = 23   

fremfor
minTable(1,1)  = 23

Og hvad nu hvis man ønskede en tabel med N diminsioner, det ville jo være umuligt med minTable() fremgangs måden.
Avatar billede kenneth_gorking Nybegynder
09. november 2006 - 22:13 #3
Hej. Min første post på eksperten :)

Der findes en meget nemmere måde at gøre det, ved hjælp af en conversion-operator. Hvis du ændre dit kode til dette:

//Table.h
erstat 'T& operator()(int i , int j);' med:
operator T**();

//Table.cpp
Erstat din 'T& operator()(int i,int j)' funktion med dette:
template <typename T> Table<T>::operator T**()
{
    return mDataMatrix;
}

Jeg prøvede og ændre din kode med mine ændringer, og det virkede helt fint.

PS. Burde dine 'Table<T>::Table<T>(...)' ikke være Table<T>::Table(...)'? Jeg kunne i hvertfald ikke kompilere det uden den ændring.
Avatar billede gulbaek Nybegynder
09. november 2006 - 23:12 #4
Sejt, så virker det jo som det skal :-) Selvom jeg ikke helt forstår hvorfor.

Og sjovt nok har jeg ingen problemer med at compile når jeg bruger Table<T>::Table<T> tilgengæld har jeg endnu ikke fundet udaf hvordan jeg kan opdele min kode i en header fil og en cpp fil, når jeg benytter mig af templates.

Bruger Visual Studio 2005 hvis det er til nogen hjælp. (Tager gerne imod anbefalinger af andre programmer, da jeg ikke er imponeret over dens code completion, virker kun halvdelen af tiden)

lars314 hvis du også vil have lidt point for dit link, så smid lige et svar.
Avatar billede bertelbrander Novice
09. november 2006 - 23:44 #5
Jeg har lavet nedenstående.
Jeg ville nok lade Array2D have et array af Array1D:

#include <iostream>

template<class T>
class Array2D
{
public:
  Array2D(int m, int n) : mNumRows(0), mNumCols(0), DataMatrix(0)
  {
      resize(m, n);
  }
  ~Array2D()
  {

  }
  class Array1D
  {
  public:
      Array1D(T* array) : Array(array)
      {}
      T& operator[] (int index)
      {
        return Array[index];
      }
      T* Array;
  };
  Array1D operator[](int index)
  {
      Array1D Array(DataMatrix[index]);
      return Array;
  }

  int numRows()const { return mNumRows; }
  int numCols()const { return mNumCols; }

  void resize(int m, int n, const T& value = 0)
  {
      int i, j;
      for(i = 0; i < mNumRows; i++)
        delete [] DataMatrix[i];
      delete [] DataMatrix;
      DataMatrix = new T * [m];
      for(i = 0; i < m; i++)
      {
        DataMatrix[i] = new T[n];
        for(j = 0; j < m; j++)
            DataMatrix[i][j] = value;
      }
  }
  int mNumRows;
  int mNumCols;
  T** DataMatrix;
};

int main()
{
  Array2D<int >My2dArray(4, 4);
  My2dArray[2][2] = 123;
  std::cout << My2dArray[2][2] << std::endl;
  My2dArray.resize(5, 5);
  My2dArray[4][4]  = 321;
  std::cout << My2dArray[4][4] << std::endl;
}
Avatar billede bertelbrander Novice
09. november 2006 - 23:45 #6
Dine template funktioner skal stå i headerfilen.

Jeg plejer at anbefale Code::Blocks
Avatar billede kenneth_gorking Nybegynder
10. november 2006 - 13:02 #7
Grunden til at det virker er at når compileren ser den første [] checker den klassen for at se om den har en 'operator [](int)' funktion, og når den ikke kan finde den prøver den at finde en anden måde at kompilere det på. Det er her den nye 'operator T**()' kommer ind i billedet, for nu kan kompileren automatiske konvertere din klasse til typen T** og så bruge [][] til at indeksere deri. Når kompileren er færdig, står der faktisk 'minTable.mDataMatrix[i][j]' hvilket nok er så hurtigt som det kan gøres :)

Jeg brugte gcc til at kompilere med, så det er nok den der har fået det galt i halsen.

Hvis din code completion ikke virker, kan det være fordi der er fejl i koden og parseren ikke kan forstå hvad der står. Det sker også tit for mig med msvc, men ligeså snart det er rettet virker det igen.
Avatar billede gulbaek Nybegynder
13. november 2006 - 20:36 #8
Må hellere til at få lukket spørgsmålet, men i skal ihvertfald have tak.
Bertelbrander hvis du også vil have lidt point for dit eksempel, kan du så ikke lige smide et svar inden alt for længe.
Avatar billede bertelbrander Novice
13. november 2006 - 21:01 #9
Jeg samler ikke på point.
Avatar billede gulbaek Nybegynder
13. november 2006 - 21:05 #10
Bare helt iorden, så skal du da også slippe :-)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester