Newsgroup: it.comp.lang.c++
Titolo: Neofita chiede aiuto: distruttori ereditati da più classi

Aiuto, sono nel panico più completo: come si fa a richiamare in una classe i
distruttori di due classi genitrici dalle quali quest'ultima deriva?
Il programma non fa niente di particolare: utilizzando le Bgi, avvia la
modalità grafica e visualizza il puntatore del mouse. Il programma termina
quando l'utente preme il tasto sinistro su una determinata area di schermo.
///////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// Il codice in questione é il seguente:
///////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\
#include "mouse.h"  // files di intestazione importati
#include "graph.h"
// questa é la classe incriminata
class App: public Graph, public Mouse {
  public:
    App();  // costruttore
    ~App();  // distruttore
    void Run();  // un metodo puramente diagnostico
};
// il distruttore: fin qui nessun problema...
App::App(): Graph(), Mouse() { }
// il famoso distruttore incriminato...
App::~App() {
  this->~Mouse();
  this->~Graph();
}
void App::Run() {
  while (!this->LeftMouseClick(0, 0, 100, 100)) {
    this->PosMouse();
    this->InitMouse(1);
  }
}
int main() {
  App A;
  A.Run();
  A.~App();
  return (0);
}
////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// Intestazione della prima classe (mouse.h):
////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
#include <dos.h>
#include <stdlib.h>
class Mouse {
    struct REGPACK *M;
  public:
    Mouse();
    ~Mouse();
    void InitMouse(int ax);
    void PosMouse();
    int MouseX();
    int MouseY();
    int OnMouseOver(int x1, int y1, int x2, int y2);
    int LeftMouseClick(int x1, int y1, int x2, int y2);
    int RightMouseClick(int x1, int y1, int x2, int y2);
};
////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\
// E il relativo corpo (mouse.cpp):
////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\
#include "mouse.h"
Mouse::Mouse() {
  M = new struct REGPACK;
}
Mouse::~Mouse() {
  delete M;
}
void Mouse::InitMouse(int ax) {
  M->r_ax = ax;
  intr(0x33, M);
}
void Mouse::PosMouse() {
  M->r_ax = 3;
  intr(0x33, M);
}
int Mouse::MouseX() {
  return (M->r_cx);
}
int Mouse::MouseY() {
  return (M->r_dx);
}
int Mouse::OnMouseOver(int x1, int y1, int x2, int y2) {
  return ((M->r_cx > x1) && (M->r_cx < x2) && (M->r_dx > y1) && (M->r_dx <
y2));
}
int Mouse::LeftMouseClick(int x1, int y1, int x2, int y2) {
  return ((OnMouseOver(x1, y1, x2, y2)) && (M->r_bx == 1));
}
int Mouse::RightMouseClick(int x1, int y1, int x2, int y2) {
  return ((OnMouseOver(x1, y1, x2, y2)) && (M->r_bx == 2));
}
/////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// Intestazione della seconda classe (graph.h):
/////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
#include "graph.h"
Graph::Graph() {
  gd = VGA;
  gm = VGAHI;
  initgraph(&gd, &gm, "C:\BC451\Bgi");
}
Graph::~Graph() {
  closegraph();
}
///////////////////////\\\\\\\\\\\\\\\\\\\\\\\\
// E il relativo corpo (graph.cpp):
///////////////////////\\\\\\\\\\\\\\\\\\\\\\\\
#include "graph.h"
Graph::Graph() {
  gd = VGA;
  gm = VGAHI;
  initgraph(&gd, &gm, "C:\BC451\Bgi");
}
Graph::~Graph() {
  closegraph();
}
Compilando il tutto con il comando:
"bcc start.cpp mouse.obj graph.obj"
mi compaiono due errori riferiti al distruttore ~App():
  "Destructor name must match the class name"
Uso il Boland C++ 4.51 sotto Win95 e i due file .obj sono stati creati e
sono funzionanti. Allora, cosa c'é di sbagliato?
Ringrazio anticipatamente chiunque possa illuminarmi, possibilmente tramite
E-mail. Se qualcuno notasse delle piccole imperfezioni concettuali o degli
errori madornali nel mio stile di programmazione, gli sarei grato se me li
facesse notare.
P.S.: per spedirmi un messaggio via e-mail elimina ".questononloscrivere"
dall'indirizzo.

 }
non serve chiamare il distruttore, il distruttore viene chiamato
automaticamente quando l'oggetto viene distrutto, in pratica dopo il
return... a questo proposito è meglio creare la applicazione con new e
cancellarla quando lo si desidera con il delete
 int main() {
   App *AP = new App;
   AP->Run();
   delete AP;
   return (0);
 }

  return (0);
Anche questa "chiamata esplicita a un distruttore"
non é corretta: il distruttore viene implicitamente
chiamato quando l'oggetto cessa di esistere (se,
come qui, é un oggetto "auto", cioé in stack, allora
il distruttore é implicitamente chiamato a qualsiasi
uscita dal blocco in cui l'oggetto é definito -- qui,
ad esempio, al return [segnalo anche che le ( )
attorno al risultato ritornato sono superflue -- non
fanno direttamente danni, ma secondo me non
aiutano la leggibilitá]).
Alex

 }
Non é vero -- questo pezzo di codice é molto peggiore di
quello piú semplice:
    int main() {
        App A;
        A.Run();
        return 0;    // niente parentesi inutili!
    }
La loro funzionalitá di base é equivalente, ma, oltre a
sprecare un pochino di tempo e di spazio, la versione
che (senza alcun beneficio) usa new e delete risulta
NON "exception-safe": se il metodo Run, o una
qualsiasi funzione che esso invoca, lancia una exception,
la versione semplice dá _comunque_ la garanzia di
eseguire il distruttore di A, quella con new/delete
invece "se lo perde per strada" (ove _servisse_
generare l'oggetto con new, meglio "depositare"
subito il suo puntatore in uno smartpointer del
tipo previsto dallo Standard C++, auto_ptr<App>,
che invocherá automaticamente il delete del
pointer che contiene, anche nel caso di uscita
dal blocco dovuta ad exception).
Alex