Soluzioni: Lezione 2
Contents
Soluzioni: Lezione 2¶

2.1+2.2+2.3 Implementazione di funzionalità aggiuntive nella classe complesso¶
complesso.h
#include <iostream>
#ifndef COMPLESSO_H
#define COMPLESSO_H
class complesso{
public:
// Constructors
complesso();
complesso(double r);
complesso (double r, double i) ;
complesso (const complesso & orig);
// Destructor
~complesso () ;
// Public class methods
double modulo () ;
double fase () ;
void stampami();
double get_real() { return m_real; };
double get_imag() { return m_imag; };
complesso somma(const complesso & orig);
complesso differenza(const complesso & orig);
complesso moltiplicazione(const double & fattore);
complesso moltiplicazione(const complesso & fattore);
// Operators overloading
complesso operator+ (const complesso & addendo);
complesso & operator= (const complesso & orig);
void operator+= (const complesso & addendo);
void operator+= (const double & addendo);
void operator-= (const complesso & addendo);
void operator-= (const double & addendo);
void operator*= (const complesso & fattore);
void operator*= (const double & fattore);
void operator/= (const complesso & fattore);
void operator/= (const double & fattore);
private:
// Private members
double m_real ;
double m_imag ;
} ;
#endif // COMPLESSO_H
complesso.cc
#include "complesso.h"
#include <cmath>
//--------------Constructors------------------
complesso::complesso ():
m_real (0.),
m_imag (0.){
std::cout << "costruzione di un numero complesso" << std::endl ;
}
complesso::complesso (double r):
m_real (r),
m_imag (0.){
std::cout << "costruzione di un numero complesso" << std::endl ;
}
complesso::complesso (double r, double i):
m_real (r),
m_imag (i){
std::cout << "costruzione di un numero complesso" << std::endl ;
}
complesso::complesso (const complesso & orig):
m_real (orig.m_real),
m_imag (orig.m_imag){
//empty
}
//--------------Destructor------------------
complesso::~complesso (){
// ~ deletes the "complesso" object and stack allocated memory.
// This is the place to clean the dinamically allocated memory.
// In this example we do not have dinamically allocated memory so the destructor is empty.
std::cout << "distruzione di un numero complesso" << std::endl;
}
//--------------Public methods---------------
double complesso::modulo (){
return sqrt(m_real * m_real + m_imag * m_imag) ;
}
double complesso::fase(){
double mod = modulo();
if (mod == 0){
throw "Parte reale e immaginaria = 0. La fase non è definita";
}
return acos(m_real/mod);
}
void complesso::stampami (){
std::cout << this->m_real << " + " << this->m_imag << "i" << std::endl ;
return ;
}
complesso complesso::somma(const complesso & orig){
complesso ret(m_real + orig.m_real, m_imag + orig.m_imag);
return ret;
}
complesso complesso::differenza(const complesso & orig){
complesso ret(m_real - orig.m_real, m_imag - orig.m_imag);
return ret;
}
complesso complesso::moltiplicazione(const complesso & fattore){
const double m_real_copy(m_real), m_imag_copy(m_imag); //definisco copie da usare nelle operazioni
double new_m_real = (m_real_copy*fattore.m_real) - (m_imag_copy*fattore.m_imag) ;
double new_m_imag = (m_real_copy*fattore.m_imag) + (m_imag_copy*fattore.m_real) ;
complesso ret(new_m_real, new_m_imag);
return ret;
}
complesso complesso::moltiplicazione(const double & fattore){
complesso ret(fattore*m_real, fattore*m_imag);
return ret;
}
//--------------Overloading---------------
complesso
complesso::operator+ (const complesso & addendo)
{
complesso somma (m_real, m_imag) ;
somma.m_real = somma.m_real + addendo.m_real ;
somma.m_imag = somma.m_imag + addendo.m_imag ;
return somma ;
}
complesso & complesso::operator= (const complesso & orig){
m_real = orig.m_real ;
m_imag = orig.m_imag ;
return *this ;
}
void complesso::operator+= (const complesso & addendo){
m_real = m_real + addendo.m_real ;
m_imag = m_imag + addendo.m_imag ;
return ;
}
void complesso::operator+= (const double & addendo){
m_real = m_real + addendo;
return ;
}
void complesso::operator-= (const complesso & addendo){
m_real = m_real - addendo.m_real ;
m_imag = m_imag - addendo.m_imag ;
return ;
}
void complesso::operator-= (const double & addendo){
m_real = m_real - addendo;
return ;
}
void complesso::operator*= (const complesso & fattore){
const double m_real_copy(m_real), m_imag_copy(m_imag); //definisco copie da usare nelle operazioni
m_real = (m_real_copy*fattore.m_real) - (m_imag_copy*fattore.m_imag) ;
m_imag = (m_real_copy*fattore.m_imag) + (m_imag_copy*fattore.m_real) ;
return ;
}
void complesso::operator*= (const double & fattore){
m_real = m_real*fattore ;
m_imag = m_imag*fattore ;
return ;
}
void complesso::operator/= (const complesso & fattore){
double denom = (fattore.m_real*fattore.m_real) + (fattore.m_imag*fattore.m_imag); // c^2 + d^2
//Controlli
if (denom==0){
if (fattore.m_real){
m_real = m_real/fattore.m_real;
return;
}
else{
std::cout << "Divisione per 0, ricontrolla inputs" << std::endl;
return;
}
}
const double m_real_copy(m_real), m_imag_copy(m_imag); //definisco copie da usare nelle operazioni
m_real = (m_real_copy*fattore.m_real + m_imag_copy*fattore.m_imag)/denom ;
m_imag = (m_imag_copy*fattore.m_real - m_real_copy*fattore.m_imag)/denom ;
return ;
}
void complesso::operator/= (const double & fattore){
if(fattore == 0){
std::cout << "Errore: Divisione per 0" << std::endl;
return;
}
m_real = m_real/fattore ;
m_imag = m_imag/fattore ;
return ;
}
main.cpp
//c++ -o main main.cpp complesso.cc
#include "complesso.h"
int main(){
//----------- Testing constructors -----------
complesso c_num1; //default
c_num1.stampami();
complesso c_num2(1); //real
c_num2.stampami();
complesso c_num3(3,5); //real + i*imag
c_num3.stampami();
complesso c_num_copy(c_num2); //copying, only real
c_num_copy.stampami();
//----------- Testing destructor in a new scope ({}) -----------
{
complesso in_new_scope;
} // here "in_new_scope" goes out of scope and destructor is called.
//----------- Testing class methods -----------
std::cout << "Il modulo di 3 +i5 è: " << c_num3.modulo() << " la fase è: " << c_num3.fase() << std::endl;
// Trying to compute the phase of 0 + i0 (0/0). Catching the exception to continue
try {
double fase_impossibile = c_num1.fase();
} catch (const char* msg) {
std::cerr << msg << std::endl;
}
//----------- Testing overloading =, +, * -----------
std::cout << "Test overloading operatori" << std::endl;
c_num1 = c_num3; // = overloading
c_num1.stampami();
c_num1 += 1; // += numero reale
c_num1.stampami();
c_num1 += c_num3; // += numero complesso
c_num1.stampami();
c_num1 -= 1; // -= numero reale
c_num1.stampami();
c_num1 -= c_num3; // -= numero complesso
c_num1.stampami();
c_num1 *= 2; // *= numero reale
c_num1.stampami();
c_num1 *= c_num3; // *= numero complesso
c_num1.stampami();
c_num1 /= 2; // /= numero reale
c_num1.stampami();
c_num1 /= c_num3; // /= numero complesso
c_num1.stampami();
//----------- End -----------
std::cout << "Al termine dell'esecuzione della funzione main" \
" verrà distrutto tutto ciò creato al suo interno: " << std::endl;
return 0;
}

2.4 Classe mioArray¶
myarray.h
#ifndef MY_ARRAY_H
#define MY_ARRAY_H
#include <iostream>
class mioArray{
public:
//Il costruttore prende in input la dimensione e inizializza il membro ( dim(d) ).
//Successivamente crea dinamicamente l'array mioarr(). Nell'espressione logica tra parentesi
//si chiede (simbolo ?) se dim > 0 (interi diversi da 0 sono true). Se è vero allora viene
//inizializzato l'array (new double[dim]) altrimenti (:) viene inizializzato l'oggetto a nullptr.
mioArray(int d): dim(d), mioarr(dim ? new double[dim] : nullptr) {};
mioArray(const mioArray& copy);
~mioArray(){ delete[] mioarr; };
bool check_idx(int idx) const;
double get1(int idx) const;
double get2(int idx) const;
void fill(int idx, double num);
void print() const; //opzionale, solo per comodità
private:
int dim;
double* mioarr;
};
#endif //MY_ARRAY_H
myarray.cc
#include "myarray.h"
mioArray::mioArray(const mioArray& copy)
: mioarr(copy.dim ? new double[copy.dim] : nullptr)
, dim(copy.dim){
/*
Copy constructor.
Viene copiato il contenuto solo se mioarr non punta a null.
*/
if (mioarr){
for(int i = 0; i < dim; i++){
mioarr[i] = copy.mioarr[i];
}
}
}
bool mioArray::check_idx(int idx) const{
/*
Semplice check tra l'indice (idx) inserito e la dimensione
dell'array (attributo della classe).
*/
return idx < dim;
}
double mioArray::get1(int idx) const{
/*
Prima funzione per richiedere un valore dall'array.
Viene svolto un check sull'indice e, se più grande della dimensione
dell'array, viene stampato un messaggio a schermo.
In ogni caso viene restituito il valore nella cella di memoria
a cui punta mioarr[idx] = *(mioarr + idx)...Qualunque essa sia!
-->Questo vuol dire che se, per sbaglio, sbagliamo l'indexing dell'array
C++ non ci avvertirà ma restituirà un valore "a caso". C++
non implementa check sui limiti degli oggetti (per mantenere alte performances).
*/
if (!check_idx(idx)){
std::cout << "L'indice inserito è più grande della dimensione dell'array" << std::endl;
}
return mioarr[idx]; //questo non da mai errore
}
double mioArray::get2(int idx) const{
/*
Seconda funzione per richiedere un valore dall'array.
Viene svolto un check sull'indice e, se più grande della dimensione
dell'array, viene lanciato un errore del tipo out_of_range con un messaggio a
piacere all'interno delle parentesi (). Se la richiesta è valida viene restituito il valore.
*/
if (!check_idx(idx)){
throw std::out_of_range ("L'indice inserito è più grande della dimensione dell'array\n");
}
return mioarr[idx];
}
void mioArray::fill(int idx, double num){
/*
Metodo per riempire l'array. Richiesto in input l'indice (idx) e il valore
da assegnare alla cella di memoria puntata da (mioarr+idx) -> mioarr[idx] = num.
Se l'indice supera la dimensione dell'array viene visualizzato a terminale un messaggio
e non viene riempita la cella di memoria.
L'operazione mioarr[idx] = num funzionerebbe anche se idx > dim.
*/
if (check_idx(idx)){
mioarr[idx] = num;
return;
}
else{
std::cout << "L'indice inserito è più grande della dimensione dell'array" << std::endl;
return;
}
}
void mioArray::print() const{
std::cout << "Mio array:" << std::endl;
for(int i = 0; i < dim; i++){
std::cout << mioarr[i] << " ";
}
std::cout << std::endl;
return;
}
main.cpp
// c++ -o main main.cpp myarray.cc
#include "myarray.h"
int main(){
int dim = 10;
mioArray arr(dim);
//Riempio l'array con dummy values
for(int i = 0; i < dim; i++){
arr.fill(i, i);
}
//Mostra contenuto
arr.print();
//modifico valore di una cella
arr.fill(1, 10.5);
//Mostra contenuto ma usando la funzione get
std::cout << "Mio array: " << std::endl;
for(int i = 0; i < dim; i++){
std::cout << arr.get1(i) << " ";
}
std::cout << std::endl;
//Proviamo a chiedere il valore dell'array per un indice > dimensione
double num = arr.get1(11);
std::cout << "La prima funzione get1 restituisce un valore " << num << " anche se l'indice richiesto 11 "\
"supera la dimensione dell\'array " << dim << std::endl;
//Proviamo a fare lo stesso con la seconda funzione.
//La sintassi try-catch viene usata per continuare nell'esecuzione del programma.
//Senza di essa il programma si bloccherebbe con messaggio di errore come output da terminale (e.what()).
try {
double error = arr.get2(11);
}
catch (const std::out_of_range& e) {
std::cout << "La seconda funzione restituisce un errore se l'indice richiesto supera "\
"la dimensione dell\'array.\nErrore: " << e.what();
}
//Test con un oggetto di tipo const
//Copiamo il contenuto di arr in un nuovo oggetto const new_arr
const mioArray new_arr(arr);
//stampiamo
new_arr.print();
std::cout << "Possiamo ricevere informazioni dall'oggetto di tipo const ad esempio " << new_arr.get2(1) << std::endl;
return 0;
}