View Full Version : [C++] definizione di una semplice classe
Devo fare un semplice esercizio di c++ che mi chiede di implementare la classe Complex.
ho fatto questi due file
complex.h
#ifndef COMPLEX_H
#define COMPLEX_H
class Complex{
public:
Complex(float=0.0, float=0.0);
void setRe(float);
float getRe();
void setIm(float);
float getIm();
void print();
private:
float re; // parte reale
float im; // parte immaginaria
}
#endif
e complex.cpp
#include <iostream>
#include "complex.h"
Complex::Complex(float r, float i){
setRe(r);
setIm(i);
}
void Complex::setRe(float r){
re = r;
}
void Complex::setIm(float i){
im = i;
}
float Complex::getRe(){
return re;
}
float Complex::getIm(){
return im;
}
void Complex::print(){
std::cout << "(" << re << "," << im << ")" ;
}
quando complilo mi da il seguente errore
complex.cpp:4: error: new types may not be defined in a return type
complex.cpp:4: error: return type specification for constructor invalid
dove sbaglio?
jappilas
24-06-2005, 20:09
scusa ma c'è una cosa che non mi torna:
tu chiami funzioni membri della classe per implementare il costruttore...mentre se non sbaglio le funzioni Set e Get dovrebbero essere attive dopo che l' oggetto è stato istanziato, non prima... e infatti tutti i costruttori che ho visto erano della forma
dato1(a); dato2(b)... ; in questo caso re(r);im(i); ...
scusa ma c'è una cosa che non mi torna:
tu chiami funzioni membri della classe per implementare il costruttore...mentre se non sbaglio le funzioni Set e Get dovrebbero essere attive dopo che l' oggetto è stato istanziato, non prima... e infatti tutti i costruttori che ho visto erano della forma
dato1(a); dato2(b)... ; in questo caso re(r);im(i); ...
nel libro che sto usando, il Deitel, usa le set nel costruttore della classe, serve per non scrivere codice duplicato, perchè sia nel costruttore che nelle set si dovrebbero fare dei controlli sulla validità dei parametri.
cmq ho ricompilato senza usare le set nel costruttore e mi da lo stesso problema. :boh:
C'era una volta un punto e virgola.
Il punto e virgola si sentiva minacciato
dalla parentesi chiusa e decise quindi
di lasciare la sua posizione e di andare
a cercar fortuna per il mondo. :D
C'era una volta un punto e virgola.
Il punto e virgola si sentiva minacciato
dalla parentesi chiusa e decise quindi
di lasciare la sua posizione e di andare
a cercar fortuna per il mondo. :D
penso che questo errore me lo ricorderò ogni volta che farò una nuova classe :D
penso che questo errore me lo ricorderò ogni volta che farò una nuova classe :D
E lo sbaglierai ogni volta come io lo sbaglio ogni volta da piu' di 10 anni a questa parte :D
E lo sbaglierai ogni volta come io lo sbaglio ogni volta da piu' di 10 anni a questa parte :D
sicuramente
ma almeno la prossima volta non rimarrò un'ora a capire casa ho sbagliato :grrr:
spero :sperem:
E lo sbaglierai ogni volta come io lo sbaglio ogni volta da piu' di 10 anni a questa parte :D
e non capisco a che diavolo serva poi quel punto e virgola oltre a farti sbagliare ogni volta...è un esempio di ridondanza sintattica veramente inutile... :mad:
Continuando l'esercizio ho scritto 2 metodi per fare la somma e la differenza
Complex Complex::add(const Complex *b) const{
Complex res;
res.setRe(re + b->getRe());
res.setIm(im + b->getIm());
return res;
}
Complex Complex::subtract(const Complex &b) const{
Complex res;
res.setRe(re - b.getRe());
res.setIm(im - b.getIm());
return res;
}
e vongono chiamati così
c=a.add(&b);
c=a.subtract(b);
secondo voi è meglio usare i puntatori come in add o i riferimenti come in subtract?
e non capisco a che diavolo serva poi quel punto e virgola oltre a farti sbagliare ogni volta...è un esempio di ridondanza sintattica veramente inutile... :mad:
Non è vero... Quella oltra ad una dichiarazione può anche essere uno statement (anzi lo è)...per questo serve il ;
class a {
...
} pippo;
Continuando l'esercizio ho scritto 2 metodi per fare la somma e la differenza
secondo voi è meglio usare i puntatori come in add o i riferimenti come in subtract?
Secondo te quale si capisce meglio ;)
Se poi consideri che in questo caso dal puto di vista della traduzione in assembly sono esattamente equivalenti cosa preferisci ?
jappilas
25-06-2005, 14:04
non facevi prima a ridefinirti gli operatori? ;)
Continuando l'esercizio ho scritto 2 metodi per fare la somma e la differenza
Complex Complex::add(const Complex *b) const{
Complex res;
res.setRe(re + b->getRe());
res.setIm(im + b->getIm());
return res;
}
Complex Complex::subtract(const Complex &b) const{
Complex res;
res.setRe(re - b.getRe());
res.setIm(im - b.getIm());
return res;
}
e vongono chiamati così
c=a.add(&b);
c=a.subtract(b);
secondo voi è meglio usare i puntatori come in add o i riferimenti come in subtract?
La consuetudine vuole che i parametri di ingresso si passino sempre con const&, mentre i parametri in uscita come puntatori.
non facevi prima a ridefinirti gli operatori? ;)
sicuramente è il modo migliore ma ancora non ci sono arrivato
La consuetudine vuole che i parametri di ingresso si passino sempre con const&, mentre i parametri in uscita come puntatori.
allora è meglio così
Complex *Complex::subtract(const Complex &b) const{
Complex *res;
res->setRe(re - b.getRe());
res->setIm(im - b.getIm());
return res;
}
Grazie
Complex *Complex::subtract(const Complex &b) const{
Complex *res;
res->setRe(re - b.getRe());
res->setIm(im - b.getIm());
return res;
}
Grazie
Questo codice è sbagliato...res non è allocato...e comunque non puoi ritornare un puntatore lì, a meno che tu non faccia un'allocazioen dinamica...
Questo codice è sbagliato...res non è allocato...e comunque non puoi ritornare un puntatore lì, a meno che tu non faccia un'allocazioen dinamica...
si è vero non l'avevo provato
questo invece dovrebbe andare bene
Complex *Complex::subtract(const Complex &b) const{
Complex *res = new Complex();
res->setRe(re - b.getRe());
res->setIm(im - b.getIm());
return res;
}
jappilas
25-06-2005, 15:58
sicuramente è il modo migliore ma ancora non ci sono arrivato
è come per le funzioni ... ;) in questo caso :Complex operator+( Complex &altro );
Complex operator-( Complex &altro ); come membri pubblici della classe, e
Complex Complex::operator+( Complex & altro ){
return Complex( re + altro.re, im + altro.im );
};
Complex Complex::operator-( Complex & altro ){
return Complex( re - altro.re, im - altro.im );
};
come implementazione,
in questo caso effettivamente crea un nuovo oggetto Complex e lo ritorna ;)
jappilas
25-06-2005, 16:03
si è vero non l'avevo provato
questo invece dovrebbe andare bene
Complex *Complex::subtract(const Complex &b) const{
Complex *res = new Complex();
res->setRe(re - b.getRe());
res->setIm(im - b.getIm());
return res;
}
uhm, crei un nuovo oggetto per usarne il puntatore, ma così mi pare resti allocato anche quando vai fuori scope
al che chiedo (perchè ho il dubbio, non è un dom retorica) : non è codice a rischio di leak? ;)
stavo dando un' occhiata al criterio RAII (http://www.hackcraft.net/raii/), e mi pare la metodica sia differente...
uhm, crei un nuovo oggetto per usarne il puntatore, ma così mi pare resti allocato anche quando vai fuori scope
al che chiedo (perchè ho il dubbio, non è un dom retorica) : non è codice a rischio di leak? ;)
ecco sono queste le cose che sto cercando di capire
però in effetti io volgio creare un nuovo oggetto che è il risulatato di una operazione fara altri 2.
Se metto un messaggio dentro il distruttore dell'oggetto riesco a capire quando viene distrutto?
si è vero non l'avevo provato
questo invece dovrebbe andare bene
Complex *Complex::subtract(const Complex &b) const{
Complex *res = new Complex();
res->setRe(re - b.getRe());
res->setIm(im - b.getIm());
return res;
}
Questa implementazione viola un principio importante che va sempre tenuto a mente quando si programma in C++:
"Resource Acquisition Is Initalisation"
In italiano significa che chi crea un oggetto ne prende anche possesso ed e' il responsabile della sua distruzione. Se crei un oggetto Complex all'interno di un altro oggetto Complex dovresti anche mettere a disposizione i servizi per la sua distruzione.
Prova questa implementazione:
Complex& Complex::subtract(const Complex &b) const{
setRe(re - b.getRe());
setIm(im - b.getIm());
return *this;
}
Se non vuoi che l'operazione modifichi l'oggetto, prova questa:
Complex& Complex::subtract(Complex* result, Complex const& a, Complex const& b) const
{
result->setRe(a.getRe() - b.getRe());
result->setIm(b.getIm() - b.getIm());
return *res;
}
Questa versione segue la convenzione matematica di mettere il risultato come primo argomento. La convenzione in C++ lo vorrebbe pero' passato come ultimo argomento. Gusto personale qui.
non è codice a rischio di leak? ;)
Mooooolto...
jappilas
25-06-2005, 16:16
Questa implementazione viola un principio importante che va sempre tenuto a mente quando si programma in C++:
"Resource Acquisition Is Initalisation"
che è appunto questo http://www.hackcraft.net/raii/ allora il mio dubbio di prima è confermato :)
[IMPORTANTE]
In italiano significa che chi crea un oggetto ne prende anche possesso ed e' il responsabile della sua distruzione.
[/ IMPORTANTE]
Se crei un oggetto Complex all'interno di un altro oggetto Complex dovresti anche mettere a disposizione i servizi per la sua distruzione.
<implementazioni a e b> ...
Questa versione segue la convenzione matematica di mettere il risultato come primo argomento. La convenzione in C++ lo vorrebbe pero' passato come ultimo argomento. Gusto personale qui.
infatti... anche se continuo ad avere l' impressione che l' operator overloading introduca meno overhead.. o sbaglio? :D
E questa ? Certo è un po' sprecona, ma viola qualche principio ?
Complex Complex::subtract(Complex const& a, Complex const& b) const
{
Complex result;
result.setRe(a.getRe() - b.getRe());
result.setIm(b.getIm() - b.getIm());
return result;
}
infatti... anche se continuo ad avere l' impressione che l' operator overloading introduca meno overhead.. o sbaglio? :D
Che io sappia l'overloading degli operatori aritmetici e di stream è tendenzialmente poco usato...probabilmente per una questione di chiarezza della classe...
infatti... anche se continuo ad avere l' impressione che l' operator overloading introduca meno overhead.. o sbaglio? :D
Mi associo a cionci, non vado d'accordo con l'overloading degli operatori :)
Ho visto cose agghiaccianti come questa:
List aList;
!List;
Ed ora dimmi l'operatore ! che operazione esegue sulla lista senza andare a guardarne l'implementazione.
L'overloading degli operatori poi hanno regole di casting implciti. precedenze e creazione di oggetti temporanei non proprio intuitive ed e' facile sbagliarsi e spesso non e' banale capire quello che succede solo a guardare il codice.
Quindi in genere cerco di evitarli e di scrivere codice che si autodocumenta anche se un po' piu' "prolisso".
Va detto pero' che nel caso dei numeri complessi l'operatore "+" e' autoesplicativo e non puo' dar adito ad alcuna confusione, quindi ci sta. In questo caso diventa quasi una questione di stile personale.
E questa ? Certo è un po' sprecona, ma viola qualche principio ?
Complex Complex::subtract(Complex const& a, Complex const& b) const
{
Complex result;
result.setRe(a.getRe() - b.getRe());
result.setIm(b.getIm() - b.getIm());
return result;
}
Alcuni compilatori sono in grado (date certe regole) di trasformarla automaticamente nella versione che ho postato con il passaggio esplicito dell'oggetto risultato. Se non lo fanno, allora viene automaticamente creata una variabile temporanea e c'e' un costruttore di copia di mezzo ed un distruttore di mezzo.
Se semplifica il codice ci sta e ben venga. Se ti accorgi che gli oggetti temporanei diventano un collo di bottiglia da qualche parte, fai sempre in tempo ad aiutare il compilatore con la mia versione.
jappilas
25-06-2005, 16:34
Mi associo a cionci, non vado d'accordo con l'overloading degli operatori :)
Ho visto cose agghiaccianti come questa:
List aList;
!List;
Ed ora dimmi l'operatore ! che operazione esegue sulla lista senza andare a guardarne l'implementazione.
L'overloading degli operatori poi hanno regole di casting implciti. precedenze e creazione di oggetti temporanei non proprio intuitive ed e' facile sbagliarsi e spesso non e' banale capire quello che succede solo a guardare il codice.
Quindi in genere cerco di evitarli e di scrivere codice che si autodocumenta anche se un po' piu' "prolisso".
ehm, sì effettivamente è meglio la comprensibilità
Va detto pero' che nel caso dei numeri complessi l'operatore "+" e' autoesplicativo e non puo' dar adito ad alcuna confusione, quindi ci sta. In questo caso diventa quasi una questione di stile personale.
sguap... -_-'
ehm , riconosco che come mio solito ragionavo per compartimenti stagni e non andavo al di là del caso specifico di poco fa... (quindi operatori A-L, +-*/<> e pochi altri)
in genere, hai ragione, meglio adottare linee guida di programmazione che massimizzino la "straigth - correctness" e comprensibilità del codice, anche in previsione un altro ci debba mettere le mani in secondo tempo) e cose come !aList di certo son tutto meno che autoesplicative... :mbe:
in genere, hai ragione, meglio adottare linee guida di programmazione che massimizzino la "straigth - correctness" e comprensibilità del codice, anche in previsione un altro ci debba mettere le mani in secondo tempo) e la !aList di certo è tutto meno che autoesplicativa... :mbe:
Un attimo, il tuo ragionamento non e' sbagliato nel caso dei Complex, soprattutto se semplifica il codice e magari lo rende anche piu' leggibile nel caso di oggetti che sono intrinsecamente numeri.
Sutter consiglia nel caso degli operatori "Do as the ints do", cioe' di fare come fanno gli interi. Se l'implementazione naturale di operatore "+" per una tua classe e' esattamente quello che tutti si aspetterebbero, va benissimo implementarlo.
La cosa da tenere a mente secondo me e' di non abusarne, cosa che vale un po' per tutti i costrutti del C++.
Complex& Complex::subtract(Complex* result, Complex const& a, Complex const& b) const
{
result->setRe(a.getRe() - b.getRe());
result->setIm(b.getIm() - b.getIm());
return *res;
}
questa è la seconda soluzione che ha postato fek
mi viene il dubbio che siccome ho passato un puntatore come primo argomento il risultato si troverà automaticamente in *result, come in C perciò questa mi sembra uguale
void Complex::subtract(Complex* result, Complex const& a, Complex const& b) const
{
result->setRe(a.getRe() - b.getRe());
result->setIm(b.getIm() - b.getIm());
}
o no?
questa è la seconda soluzione che ha postato fek
mi viene il dubbio che siccome ho passato un puntatore come primo argomento il risultato si troverà automaticamente in *result, come in C perciò questa mi sembra uguale
o no?
Si' le due versioni sono quasi esattamente equivalenti.
Nel secondo caso ritorni anche una reference al risultato e la cosa ti permette di concatenare la chiamata alla funzione con una chiamata ad un metodo della classe Complex, ad esempio cosi':
Complex result;
float realPart = subtract (&result, a, b).getRe();
che e' piu' concisa ed e' equivalente a:
Complex result;
subtract (&result, a, b);;
float realPart = result.getRe();
Se pensi che questo genere di costrutto non ti servira' mai oppure rende il tuo codice piu' complesso del necessario, usa pure la versione con void che va benissimo. Caso mai ti servisse, fai sempre in tempo a modificare il metodo per tornare il risultato come reference.
Se pensi che questo genere di costrutto non ti servira' mai oppure rende il tuo codice piu' complesso del necessario, usa pure la versione con void che va benissimo. Caso mai ti servisse, fai sempre in tempo a modificare il metodo per tornare il risultato come reference.
si in effetti può essere utile.
adesso cerco qualcos'altro da chiedervi :D
si in effetti può essere utile.
adesso cerco qualcos'altro da chiedervi :D
Non scrivere qualcosa perche' puo' esserti utile, scrivila solo se effettivamente ti serve :)
ghiotto86
25-06-2005, 18:33
e non capisco a che diavolo serva poi quel punto e virgola oltre a farti sbagliare ogni volta...è un esempio di ridondanza sintattica veramente inutile... :mad:
è come se facessi un typedef , definisci un nuovo tipo.
la classe è solo un interfaccia complessa che definisce dati e istruzioni e quindi come in ogni cosa nel c++ di questo tipo va col ;
io quando inizio a crare una classe prima che dimentichi quel famigerato ;
faccio
class X{};
e via :D
ghiotto86
25-06-2005, 18:34
Non scrivere qualcosa perche' puo' esserti utile, scrivila solo se effettivamente ti serve :)
mentalità RISC :sofico:
io quando inizio a crare una classe prima che dimentichi quel famigerato ;
faccio
class X{};
e via :D
Anche io :)
Ho fatto delle prove per vedere quando vengono creati gli oggetti e quando vengono distrutti. Ho aggiunto delle istruzioni per stampare dei messaggi nel costruttore e nel distruttore. nella main creo 3 oggetti, poi ad uno di questi gli assegno la somma degli altri 2.
Con la soluzione di cionci mi ha dato questo:
(1,1)Creato
(0,0)Creato
(2,2)Creato
(1,1)
(2,2)
(0,0)Creato
(3,4)Distrutto
(3,4)
(2,2)Distrutto
(3,4)Distrutto
(1,1)Distrutto
l'oggetto temporaneo viene effettivamente creato
Con l'overloading degli operatori:
(1,1)Creato
(0,0)Creato
(2,2)Creato
(1,1)
(2,2)
(3,3)Creato
(3,3)Distrutto
(3,3)
(2,2)Distrutto
(3,3)Distrutto
(1,1)Distrutto
anche qui c'è loggetto temporaneo
Con la funzione di fek:
(1,1)Creato
(0,0)Creato
(2,2)Creato
(1,1)
(2,2)
(3,3)
(2,2)Distrutto
(3,3)Distrutto
(1,1)Distrutto
c'e un oggetto in meno.
io quando inizio a crare una classe prima che dimentichi quel famigerato ;
faccio
class X{};
e via
io di solito quando apro una parentesi graffa la chiudo sempre. Seguirò il tuo metodo per le classi.
c'e un oggetto in meno.
Hai fatto una cosa furba, hai provato empiricamente che una versione e' piu' veloce di un'altra.
Ora pero', la scelta su quale delle due usare dipende per prima cosa dalla leggibilita' del tuo codice: scegli la versione che rende il tuo codice piu' semplice e chiaro da leggere, ignora per ora la velocita' di esecuzione.
Fenomeno85
25-06-2005, 20:17
C'era una volta un punto e virgola.
Il punto e virgola si sentiva minacciato
dalla parentesi chiusa e decise quindi
di lasciare la sua posizione e di andare
a cercar fortuna per il mondo. :D
bellissima questa :D :asd: .... me la segno giù :D
~§~ Sempre E Solo Lei ~§~
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.