Newsgroup: it.comp.lang.c++
Titolo: problema con le interfacce

Sto provando a fare quello che facevo in java definendo delle interfacce
e poi implementandole in classi. Solo che, sicuramente a causa della mia
ignoranza del c++, non riesco a farlo perfettamente.
Mi spiego:
ho una interfaccia cosi' definita
namespace Turbo
{
  class Source
  {
  public:
    virtual Data * generateData (int size) = 0;
  };
}
poi volgio implementare il tutto in una sorgente pn:
namespace Turbo
{
  class PNSource:public Source
  {
  public:
    PNSource (int r);
    ~PNSource ();
    Data* generateData (int size) = 0;
  private:
    int _r;
  };
}
di cui poi per ora ho una interpretazione abbastanza banale
using namespace Turbo;
PNSource::PNSource (int r) {
        _r = r;
}
PNSource::~PNSource () {
}
Data * PNSource::generateData(int size) {
        return NULL;
}
Bene, se compilo col g++ 4.0.2 di debian testing ottengo
bott@pcimg12:~/Progetti/turbo$ make
make  all-recursive
make[1]: Entering directory `/home/bott/Progetti/turbo'
Making all in src
make[2]: Entering directory `/home/bott/Progetti/turbo/src'
if g++ -DHAVE_CONFIG_H -I. -I. -I.. -I.. -I..   -Wall -g  -MT main.o -MD
-MP -MF ".deps/main.Tpo" \
  -c -o main.o `test -f 'main.cc' || echo './'`main.cc; \
then mv -f ".deps/main.Tpo" ".deps/main.Po"; \
else rm -f ".deps/main.Tpo"; exit 1; \
fi
if g++ -DHAVE_CONFIG_H -I. -I. -I.. -I.. -I..   -Wall -g  -MT pnsource.o
-MD -MP -MF ".deps/pnsource.Tpo" \
  -c -o pnsource.o `test -f 'pnsource.cc' || echo './'`pnsource.cc; \
then mv -f ".deps/pnsource.Tpo" ".deps/pnsource.Po"; \
else rm -f ".deps/pnsource.Tpo"; exit 1; \
fi
source.h:10: warning: 'class Turbo::Source' has virtual functions but
non-virtual destructor
pnsource.h:11: warning: 'class Turbo::PNSource' has virtual functions
but non-virtual destructor
g++ -Wall -g    -o turbo  main.o pnsource.o
make[2]: Leaving directory `/home/bott/Progetti/turbo/src'
make[2]: Entering directory `/home/bott/Progetti/turbo'
make[2]: Leaving directory `/home/bott/Progetti/turbo'
make[1]: Leaving directory `/home/bott/Progetti/turbo'
bott@pcimg12:~/Progetti/turbo$
Come faccio a far sparire quei warning?

 Come faccio a far sparire quei warning?
i messaggi di errore sono piuttosto esplicativi, non hai dichiarato il 
distruttore virtuale. Risolvi così:
namespace Turbo
{
   class Source
   {
   public:
     virtual ~Source() {}
     virtual Data * generateData (int size) = 0;
   };
}
-- 
MSN: sirpsycho_78 -at- hotmail dot com
"Arditi, com'altro nomare questi baldi fiori del regime che osarono 
porre un imperativo categorico tra le sabbie bolsceviche di Marte."

 
e' vero, funziona! grazie. Pero' non mi e' chiara una cosa: se io lo
metto con le {} e' come se scrivessi l'implementazione del metodo, no?
Ma allora non e' piu' una classe completamente astratta, o sbaglio?

 Ma allora non e' piu' una classe completamente astratta, o sbaglio?
non sbagli, il problema è che in C++ una classe *deve* avere il suo 
distruttore. Ad esempio:
class Abs {
   virtual ~Abs() = 0;
};
può essere scritto (così facendo obblighi le specializzazioni di Abs a 
definire il distruttore) ma di fatto devi comunque fornire 
l'implementazione del distruttore di Abs:
class Abs {
   virtual ~Abs() = 0;
};
Abs::~Abs()
{}
quindi tanto vale scrivere come ho fatto nell'esempio del mio primo post.


 distruttore. 
ottimo, grazie

 distruttore.
Non e' obbligatorio avere un distruttore per ogni classe.
Il distruttore serve solo se c'e' qualcosa da distruggere o, nel caso di 
classi contenenti almeno un'altra funzione virtuale.
In questo secondo caso, che e' quello in questione, e' fortemente 
consigliato definire un distruttore virtuale (vuoto se non c'e' niente 
da distruggere). Infatti, se non venisse definito, e se si chiamasse 
"delete p", dove p e' un puntatore a un oggetto della classe base (nel 
tuo caso a un oggetto di tipo Source), non verrebbe chiamato l'eventuale 
eventuale distruttore della classe reale dell'oggetto puntato.
In pratica, anche se non si ha intezione di definire distruttori nelle 
sottoclassi, e' sempre meglio definire un distruttore virtuale vuoto 
nelle classi che hanno almeno un altro metodo virtuale.
Invece, se una classe non ha nessun metodo virtuale, come la maggior 
parte delle classi della libreria standard, e' meglio non definire un 
distruttore se non c'e' niente da distruggere. Infatti, se tale metodo 
e' vuoto e non virtuale e' completamente inutile, e se e' vuoto e 
virtuale trasformerebbe in virtuale una classe concreta (cioe' priva di 
funzioni virtuali). Gli oggetti di classi concrete sono piu' compatti 
perche' non hanno il puntatore alla vtable.
-- 
     Carlo Milanesi
 
http://digilander.libero.it/carlmila

 Non e' obbligatorio avere un distruttore per ogni classe.
12.4  Destructors                                         [class.dtor]
[...]
3 If  a  class has no user-declared destructor, a destructor is declared
   implicitly.  An implicitly-declared destructor  is  an  inline  public
   member  of its class. [...]
quindi, ogni classe *ha* un distruttore, che sia definito da te oppure no.


 eventuale distruttore della classe reale dell'oggetto puntato.
Non è corretto. Se si invoca 'delete' su un puntatore a classe base, 
sprovvista di distruttore virtuale, che punta a un oggetto di una classe 
derivata, il comportamente è *indefinito*. Può darsi che in alcune 
circostanze e con alcuni compilatori l'effetto visisbile sia la mancata 
chiamata del distruttore della classe derivata, ma questo è un fatto 
contingente che rientra nella categoria del comportamento indefinito. (Con 
GCC, in certe condizioni, l'effetto visibile è anche un bel "segmentation 
fault".)
Max
 

 quindi, ogni classe *ha* un distruttore, che sia definito da te oppure no.
OK, e' un discorso analogo ai costruttori.
Avevo interpretato la frase "in C++ una classe *deve* avere il suo 
distruttore" come "il programmatore farebbe bene a definire sempre un 
distruttore".
Conosco alcuni programmatori che appena creano una classe definiscono 
comunque subito un distruttore virtuale, e questo non mi sempra sempre 
opportuno. Per esempio, nella definizione del template di classe 
std::complex certamente non viene definito un distruttore anche se il 
compilatore ne crea uno.
