Newsgroup: it.comp.lang.c++
Titolo: uso di una classe derivata

ciao a tutti,
ho una questione da porvi. Poco tempo fa ho notato del codice del
tipo:
class Base
{
  protected:
  int variabile;
};
class Derived : public Base
{
  public:
  SetVariable(int value){variable = value;}
}
int main ()
{
  Base *b = new B();
  (Derived* b)->SetVariable(5);
  return 0;
}
Questa cosa non mi quadra tanto dal momento che se avessi una derived
di questo tipo:
class Derived : public Base
{
  public:
  SetVariable2(int value){variable2 = value; variable1 = variable2;}
  protected:
  int variable2;
}
una classe istanziata derived e' allocata anche con la variabile2
mentre quella base no.
Qualcuno mi potrebbe illuminare se il primo esempio e' c++ valido
oppure mi potrei aspettare comportamenti strani o magari alcuni
compilatori mi generano robe che non funzionano come negli altri.
Inoltre se le variabili attributo di una classe vengono istanziate, la
parte relativa alla funzione e' istanziata anch'essa magari con un
puntatore al codice operativo legato alla funzione?
grazie e ciao!
w.

Nel tuo codice ci sono vari errori di grammatica e non compila nemmeno :)
L'ho sistemato un po':
class Base {
  protected:
  int variabile1;
};
class Derived : public Base {
  public:
  void SetVariabile2(int value){
      variabile2 = value;
      variabile1 = variabile2;
  }
  protected:
  int variabile2;
};
int main ()
{
  Base *b = new Base();
  ((Derived*)b)->SetVariabile2(5);
  return 0;
}
La motivazione del perch� funzioni non la conosco, ma probabilmente � una 
delle seguenti:
1. Il cast a Derived rende b un istanza di Derived a tutti gli effetti (ma 
non ne sono tanto sicuro)
2. Il codice non va in crash per puro caso, e quindi il comportamento � 
indefinito.
Aspettiamo risposte da parte di qualcuno pi� informato :-) 

 Aspettiamo risposte da parte di qualcuno pi informato :-)
Il cast a Derived fa sì che b sia trattato effettivamente come un
oggetto di tipo d.
Quello che succede con la chiamata "((Derived*)b)->SetVariabile2(5);",
è che viene chiamato il metodo Derived::SetVariabile(5).
Poiché in questo caso il metodo non è virtuale, si comporta come una
normale funzione a cui viene passato anche un puntatore all'oggetto
correlato ("this").
Se fosse stato un metodo virtuale, la risoluzione sarebbe passata per
la vtable di Derived.
Evidentemente il riferimento a variabile2 va a scrivere su una parte
dello heap che sta all'interno del segmento a disposizione del
processo, e quindi il sistema operativo non dà SIGSEGV. Più
esattamente, si prende l'indirizzo base dell'oggetto ("this"), e il
compilatore aggiunge l'offset relativo a variabile2, anche se di fatto
non c'è (immagino sia un byte).
Tuttavia, quello spazio potrebbe essere di qualcun altro al di fuori
di b, visto che noi sappiamo che b è in realtà un oggetto di tipo
Base, provocando una corruzione dei dati. In effetti, il codice non va
in crash per puro caso.
Prova ad allocare b sullo stack anziché sullo heap, e a impostare una
variabile intera "variabile3" appena sotto.
int main ()
{
  Base b;
  volatile int variabile3 = 100;
  ((Derived*)&b)->SetVariabile2(5);
  if (variabile3 == 100)
    cout << "Clean" << endl;
  else
    cout << "Dirty" << endl;
}
Il controllo è per vedere se la variabile viene sporcata.
Compila senza ottimizzazioni (-O0 con gcc), anche se c'è volatile. Non
si sa mai.
Non l'ho provato perché sono di fretta, ma con un po' di fortuna
dovrebbe dire "Dirty", anche se non è detto.
Sponsorizzato dalla campagna per l'abolizione del cast in stile C a
favore di quelli in stile C++. :-p
Ciao,
Matteo

dovrebbe dire "Dirty", anche se non � detto.
Stampa Dirty solo se c'� volatile e se si passa -O al compilatore.