vuoi
o PayPal
tutte le volte che vuoi
Il programma permette di implementare una classe 'matrice' (di dimensioni fisse 3x3 e a valori interi) che supporti le seguenti condizioni:
1-Due costruttori: uno senza inizializzazione (che mette a zero tutti gli elementi) e uno che permetta una dichiarazione del tipo,matrice m2(1,0,4,5,5,0,0,4,-3);
2-Una funzione membro print() che stampa in forma righe e colonne la matrice,m2.print();
3-Una funzione membro setidentity che imposta la matrice al valore "identita' 3x3",m2.setidentity();
4-Due funzioni di accesso in lettura/scrittura ai singoli elementi di matrice,int b = m2.getitem(i,j),m2.setitem(i,j,valore);
5-L'uso di operatori tra oggetti di tipo matrice, quali ad esempio,l'inserzione su output stream (sempre in forma righe e colonne).
#include <iostream>
using namespace std;
// modello della classe matrix
class matrix{
public:
matrix(int,int,int,int,int,int,int,int,int);
matrix();
void setidentity();
int getitem(int,int);
void setitem(int,int,int);
void print();
private:
int dati[3][3];
// gli operatori overloadati non sono funzioni membro, ma devono poter
accedere
// ai dati private di ogni istanza della classe, dunque li si dichiara
come friend:
friend ostream& operator<< (ostream&, const matrix&);
friend matrix operator+ (const matrix&, const matrix&);
friend matrix& operator+= (matrix&, const matrix&);
friend matrix operator* (const matrix&, const matrix&);
friend matrix operator* (const int, const matrix&);
friend bool operator== (const matrix&, const matrix&);
};
// codice della classe matrix
matrix::matrix(){
// costruttore di default: tutti gli elementi a zero.
int i,j;
for (i=0;i<=2;i++){
for (j=0;j<=2;j++){
dati[i][j]=0;
}
}
}
matrix::matrix(int a11, int a12, int a13, int a21, int a22, int a23, int a31,
int a32, int a33){
// costruttore con valori dati nella dichiarazione
dati[0][0]=a11;
dati[0][1]=a12;
dati[0][2]=a13;
dati[1][0]=a21;
dati[1][1]=a22;
dati[1][2]=a23;
dati[2][0]=a31;
dati[2][1]=a32;
dati[2][2]=a33;
}
void matrix::setidentity(){
// imposta la matrice all'identita' 3x3
int i,j;
for (i=0;i<=2;i++){
for (j=0;j<=2;j++){
dati[i][j]=(i==j?1:0);
// questo e' un delta di Kronecker
}
}
}
int matrix::getitem(int row, int column){
// funzione membro per leggere da fuori un elemento
if (row>2 || row<0 || column>2 || column<0) return 0;
return dati[row][column];
}
void matrix::setitem(int row, int column, int newvalue){
// impostare da fuori il valore di un elemento di matrice
if (row>2 || row<0 || column>2 || column<0) return;
dati[row][column] = newvalue;
}
void matrix::print(){
// stampa in forma matriciale (righe e colonne: vedi l'uso di endl e di
"\t") int i,j;
for (i=0;i<=2;i++){
for (j=0;j<=2;j++){
cout << dati[i][j] << "\t";
}
cout << endl;
}
}
//overloading degli operatori:
ostream& operator<< (ostream& os, const matrix& m){
// vedi print()
int i,j;
for (i=0;i<=2;i++){
for (j=0;j<=2;j++){
os << m.dati[i][j] << "\t";
}
os << endl;
}
// viene ritornato un *riferimento* allo stesso oggetto os che e' passato,
senza farne
// una copia nuova (infatti il tipo di dato di ritorno e' ostream& e non
ostream!)
return os;
}
matrix operator+ (const matrix& m1, const matrix& m2){
// anche se la funzione non modifica i valori di m1 e m2, e sarebbe
indifferente
// dichiarare parametri matrix o matrix&, per evitare la creazione di due
nuovi oggetti
// si preferisce usare la & (risparmiando le risorse necessarie per la
copia).
// L'uso di "const" serve ad evitare che la funzione (mal scritta) sia in
grado di
// modificare gli argomenti: il compilatore darebbe un errore.
// somma elemento per elemento
int i,j; // indici del risultato...
matrix sum;
for (i=0;i<=2;i++){
for (j=0;j<=2;j++){
// elemento (i,j) della somma:
sum.setitem(i,j,m1.dati[i][j]+m2.dati[i][j]);
}
}
// viene ritornato un *nuovo* oggetto di tipo matrix! (non c'e' & dopo
matrix nel tipo
// di ritorno)
return sum;
}
matrix& operator+= (matrix& m_dest, const matrix& m_source){
// ecco un caso in cui m_source non viene modificata (ed e' const), mentre
i valori di
// m_dest vanno modificati, e non si usa la parola chiave const. Inoltre,
la funzione
// in se' rende a sua volta un riferimento a m_dest per permettere
espressioni come:
// m3 = (m2+=m1);
// Il valore di ritorno non viene usato da istruzioni come:
// m5+=m4;
// appoggiandosi all'operatore +, gia' overloadato, basta scrivere:
m_dest = m_dest + m_source;
return m_dest;
}
matrix operator* (const matrix& m1, const matrix& m2){
//prodotto tra matrici: la formula richiede l'uso di tre indici...
int i,j; // indici del risultato...
int k; // questo per il calcolo dell'elemento della matrice prodotto
int temp;
matrix prod;
for (i=0;i<=2;i++){
for (j=0;j<=2;j++){
// elemento (i,j) del prodotto:
temp=0;
for (k=0;k<=2;k++){
temp+=m1.dati[i][k]*m2.dati[k][j];
}
prod.setitem(i,j,temp);
}
}
return prod;
}
matrix operator* (const int number, const matrix& m1){
// prodotto per scalari
// come per il costructor, possono convivere piu' funzioni con lo stesso
nome, // con identico tipo di dato di ritorno, ma diversi argomenti: il
compilatore
// si occupera' di chiamare di volta in volta la corretta versione della
funzione;
// cosi' e' risolta l'ambiguita' tra (matrix)*(matrix) e (int)*(matrix),
ovvero
// tra prodotto tra matrici e per scalari.
int i,j; // indici del risultato...
matrix scalar_prod;
for (i=0;i<=2;i++){
for (j=0;j<=2;j++){
scalar_prod.setitem(i,j,m1.dati[i][j]*number);
}
}
return scalar_prod;
}
bool operator== (const matrix& m1, const matrix& m2){
//serve ad estendere l'operatore == ad oggetti matrix, rendendo vero
// se e solo se gli elementi coincidono uno ad uno.