Simone Bacciglieri ha scritto:
perchè il listato di prova allegato mi produce questo output?
-----------------------------------------------------------------------------------
Creo punto
Distruggo punto
x= 0
y= 0
Distruggo punto
----------------------------------------------------------------------------------
E poi: cosa devo usare per poter stampare a video una stringa partendo da
colonna x e riga y?
Dipende dalla piattaforma: su Unix, [n]curses. Per un quick hack, vedi
le sequenze di escape VT100 - a console funzionano (e qualche volta
anche in emulatori di terminale come putty, ma se si comincia a porsi
questo problema conviene passare a [n]curses).
------------------------------------------------------------------------
#include <iostream>
using namespace std;
class punto {
public:
punto();
~punto();
Qui non hai esplicitato il costruttore di copia (copy constructor,
abbreviato copy ctor): il compilatore ne fornisce uno di default che
nel tuo caso (probabilmente per caso) si comporta in modo adeguato.
punto(const punto& other): x(other.x), y(other.y) { }
void impostapunto(int,int);
void printpunto(void);
private:
int x;
int y;
};
punto::punto()
{
cout << "\nCreo punto\n";
Sarebbe meglio:
punto::punto(): x(0), y(0)
{
cerr << "\nCreo punto\n";
}
x=0;
y=0;
}
punto::~punto()
{
cout << "\nDistruggo punto\n";
cerr << "\nDistruggo punto\n";
}
void punto::impostapunto(int a,int b)
{
x=a;
y=b;
}
Cosa ti ha fatto di male l'operatore di assegnamento ?
void punto::printpunto(void)
{
cout << "\nx= " << x << "\ny= " << y << "\n\n";
}
Cosa ti ha fatto di male << ?
class usa {
public:
void usapunto(punto);
};
Ecco il tuo problema ...
void usa::usapunto(punto p)
{
int y=10;
int x=11;
p.impostapunto(y,x);
}
La funzione usapunto() dichiara il proprio argomento *per valore*, il
che significa
che:
- viene fatta una copia del parametro nell'argomento p, usando il
costruttore di copia;
- tale copia p è locale alla funzione;
- x e y sono impostati (scambiati ?) in p;
- p viene distrutto in uscita dalla funzione.
main()
{
punto pu;
usa us;
us.usapunto(pu);
pu.printpunto();
}
Qui pu ha x = 0 e y = 0, usapunto() come sopra indicato non ne cambia i
valori e printpunto() stampa appunto 0 e 0. Temo che tu soffra di
sindrome da Visual Basic, è l'unico linguaggio che mi venga in mente a
passare per riferimento i parametri. Visual Basic ha rovinato parecchia
brava gente, ma si può rimediare se viene curato per tempo :->
Ti propongo quanto segue:
#include <iostream>
// Non è buon stile usare 'using namespace std;' ...
class punto {
public:
punto(): x(0), y(0) { } // Nota 1
punto(int xx, int yy): x(xx), y(yy) { } // Nota 2
punto(const punto& other): x(other.x), y(other.y) { } // Nota 3
~punto() { } // Nota 4
punto& operator= (const punto& p) { // Nota 5
if (this != &p) { // Nota 6
x = other.x;
y = other.y;
}
return *this;
}
// Nota 7
private:
int x;
int y;
}
Note:
[1] la notazione x(0) è una buona abitudine, si chiama 'member
initizaliation syntax', è sempre più efficiente che scrivere x=0 nel
corpo del costruttore (vale per i costruttori) altrimenti C++ prima
inizializza x a un valore di default (int è un caso speciale e viene
inizializzato a ... quel che c'è in RAM) e poi eseguendo x = 0 ci passa
sopra.
[2] questo è un costruttore che serve a creare punti diversi da (0, 0)
senza dover fare l'inefficiente giro sopra indicato (prima li creo e
subito dopo li imposto).
[3] questo è il costruttore di copia, viene usato quando si crea una
istanza di "punto" per copia di una esistente.
[4] c'è una regola empirica detta 'rule of three': se hai bisogno di un
costruttore di copia o di un operatore di assegnamento o di un
distruttore, allora con tutta probabilità hai bisogno di tutti e
tre. Nel caso in esame tecnicamente potresti fare a meno di tutti a tre,
ma mi è parso il caso di sfruttare la semplicità dell'esempio.
[5] questo è l'operatore di assegnamento e fa le veci di impostapunto(),
nel senso che consente di scrivere
p = punto(11, 17);
senza perdita di efficienza.
[6] quando si scrive l'operatore di assegnamento, occorre chiedersi se
per caso non ci si sta scrivendo addosso (nei costruttori non può
succedere, creano un oggetto nuovo); ancora una volta nel caso in esame
non succederebbe niente, ma in generale il problema bisogna porselo e
questo è un modo di far sapere a chi legge il codice che me lo sono
posto. Tecnicamente questo approccio non è correttissimo per questioni
legate alle eccezioni, ma mi pare il caso di affrontare una cosa alla
volta.
[7] ora devo uscire, rimando a domani un piccolo esempio di definizione
di operator<< che consentirà di scrivere:
cout << p;
per l'output di punti.
Per venire al problema, in barba a chi mi accusa di essere troppo
conciso, bisogna sapere cosa si intende ottenere. Se usapunto() *deve*
modificare il punto (pratica sconsigliatissima, mi riprometto di
tornarci sopra), basta:
usapunto(punto& p) {
...
}
altrimenti usapunto() non ti serve e ciò di cui hai bisogno è
il costruttore
punto p(11, 17);
o l'operatore di assegnamento
p = punto(11, 17);
Infine mi scuso per non aver avuto il tempo di provare quanto sopra
al compilatore -mi riprometto un seguito.
Davide Bolcioni
--
Linux - the choice of a GNU generation.
|