Newsgroup: it.comp.lang.c++
Titolo: classe matrix delle FAQ

sto cercando di capire la classe d'esempio matrix delle FAQ (domanda 8,
Come posso allocare dinamicamente una matrice a piu` dimensioni e 
utilizzare la notazione M[i][j]?)
mi riferisco all'approccio "di basso livello":
template<class T>
class matrix {
  T* body;
  int x; int y;
  public:
  void setSize(int x, int y) {
    if(body) delete[] body; // getta tutto
    body = new T[x*y]; // riparte
    this->x = x;
    this->y = y;
  }
  void getSize(int &x, int &y) {
    x = this->x;
    y = this->y;
  }
  matrix(): body(0) {}
  matrix(int x, int y): body(0) { setSize(x,y); }
  ~matrix() { if(body) delete[] body; }
  T* operator[](int i) { return body+i*y; }
  const T* operator[](int i) const { return body+i*y; }
};
Ho dei problemi a comprendere il funzionamento dei due operatori [].
Supponendo di aver costruito l'oggetto matrix Mat(3, 4), quando scrivo
Mat[2][3] cosa capita? Mat[2] mi dovrebbe restituire il puntatore
Mat.body + 2*4; a questo punto però non ho + un oggetto matrix, ma un
ptr a un tipo T... come faccio ad applicare l'operatore [] scrivendo di
seguito: [3]?
Scusate, sono un po' tonto..ho bisogno di una spiegazione passo x passo!
NB stessi problemi di comprensione anche x quanto riguarda la classe
matrix implementata x mezzo degli oggetti vector<T>
-- 
Davide Cavallari

 matrix implementata x mezzo degli oggetti vector<T>
Adesso direte (a ragione) che sono un po' fissato:
Ma non vi sembrerebbe più logico proporre una versione basata sui
valarray invece che sui vector? (in pratica basta sostituire tutti i
"vector" con "valarray")
template<class T> class matrix
{
    typedef std::valarray<T> riga;
    std::valarray<riga> body;
    void setSize(int x, int y)
    {
        body.resize(0); // getta tutto
        body.resize(x); // riparte
        for(int i=0; i<x; ++i)
        {
            body[i].resize(0); // perche' questa riga non c'e' nelle FAQ con
vector?
            body[i].resize(y);
        }
    }
    public:
    matrix() {}
    matrix(int x, int y) { setSize(x,y); }
    std::valarray<T>& operator[](int i) { return body[i]; }
    const std::valarray<T>& operator[](int i) const { return body[i];}
};
--
Gerolamo
Using: Win2000 Pro, Borland C++ Compiler 5.5.1
Listening: Pink Floyd - Comfortably Numb

"vector" con "valarray")
ehm..forse sě, ma non hai cmq risolto il mio problema con gli operatori
[] !!
-- 
Davide Cavallari

 matrix implementata x mezzo degli oggetti vector<T>
vediamola:
#include <vector>
template<class T> class matrix
{
    typedef std::vector<T> riga;
    std::vector<riga> body;
    public:
    void setSize(int x, int y)
    {
        body.resize(0); // getta tutto
        body.resize(x); // riparte
        for(int i=0; i<x; ++i)
            body[i].resize(y);
    }
    void getSize(int &x, int &y)
    {
        x = body.size();
        if(x) y=body[0].size();
        else y=0;
    }
    matrix() {}
    matrix(int x, int y) { setSize(x,y); }
    // non occorre dtor esplicito, quello di
    // default e` OK
    std::vector<T>& operator[](int i) { return body[i]; }
    const std::vector<T>& operator[](int i) const { return body[i]; }
};
allora...
quando faccio
matrix<float> Mat(3,4);
lui costruisce un
vector<vector<float> > body;
e poi lo dimensiona prima in una dimensione con
body.resize(x);
e poi nell'altra con
for(int i=0; i<x; ++i)
        body[i].resize(y);
A questo punto diciamo che costruiamo, come prima, un matrix cosě:
matrix<float> Mat(3,4);
A questo punto con Mat[2][3] cosa succede?
Succede che Mat[2] e' implementato da
const std::vector<T>& operator[](int i) const { return body[i]; }
che, nel nostro caso, restituisce un const std::vector<float>&
Ok.
a questo punto viene invocato l'operatore [] implementato dalla
libreria standard per i vector<T> e abbiamo il nostro elemento.
Ovvero, nel nostro esempio, troviamo il terzo elemento del
vector<float> che era stato restituito con Mat[2]
--
Gerolamo
Using: Win2000 Pro, Borland C++ Compiler 5.5.1
Listening: Gorillaz - Punk

libreria standard per i vector<T> e abbiamo il nostro elemento.
ehhh, l'overloading... :)   grazie1000
un'ultima questione: vengono definiti due operatori []:
 
 std::vector<T>& operator [] (int i) { return _body[i]; } 
 const std::vector<T>& operator [](int i) const { return _body[i]; }
Il compilatore, da quello che hai detto, riesce a riconoscere quando č
sufficiente usare il "selettore":
const std::vector<T>& operator [](int i) const { return _body[i]; }
o quando invece deve invocare il "modificatore":
std::vector<T>& operator [] (int i) { return _body[i]; }
ad esempio, nel caso venisse scritto qualcosa del tipo:
Mat[2][3] = 3.11
Mi pare dunque di capire che *di default* vengono chiamati i selettori;
qualora questo non fosse possibile, vengono allora chiamati i
modificatori. 
Questa regola che ho dedotto č generale? (e, soprattutto, č vera?)
-- 
Davide Cavallari

 modificatori.
Non e' esatto, il compilatore non e' un indovino. La scelta e'
determinata dal fatto che uno dei due operatori e' dichiarato "const" ed
e' quindi chiamato su oggetti dichiarati const.
Ciao,
Nicola

e' quindi chiamato su oggetti dichiarati const.
allora se creo un oggetto così:
...
matrix<float> Matrice;
...
cout << Matrice[2][3] << endl;
...
Matrice non è un oggetto const, quindi quale dei due operatori [] viene
invocato avendo scritto Matrice[2]?
-- 
Davide Cavallari

 invocato avendo scritto Matrice[2]?
Quello non const. Se Matrice non avesse l'operatore[] non const
allora il compilatore prova ad usare quello const
che nel caso std::cout << Matrice[2][3]  va bene
ma se tu volessi fare Matrice[2]  ...... non compilerebbe.
La regola e': se un ogetto e' const possono essere applicati su di
lui solo metodi const ( a meno di cast ).
Se un ogetto e' non const possono essere applicati su di lui sia i
const che i non const. Se ci sono entrambi la scelta cade sui
non const.
-- 
Posted from 
nts-03.mm.eutelsat.org
 [194.214.173.15] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG