Newsgroup: it.comp.lang.c++
Titolo: Conversione da Base* a Derivata* e funzione insert

Salve,
ho 2 cose semplici da chiedere:
1)come mai non si può convertire un puntatore a classe base in un puntatore
a classe derivata?
Forse perché la derivata è più aggiornata?
Es:
#include <iostream>
class Base {
 public :
 void ciao () {
  std::cout << "ciao da base" << std::endl;
 };
};
class Der : public Base {
 public :
  void ciao () {
  std::cout << "ciao da der" << std::endl;
 };
};
Der* objder = new Base;  // Dice che non si può convertire un Base* in un
Der*
2) Ho letto nel libro di Lippman che la funzione insert della classe string
accetta come secondo parametro una stringa,
una stringa stile C oppure un carattere. Allora perché in questo caso non
funziona:
string s = "ciao";
.....
s.insert (1, 'X'); // se invece metto X tra doppi apici ("X") funziona!
Grazie

 s.insert (1, 'X'); // se invece metto X tra doppi apici ("X") funziona!
Il motivo e' semplice,  questo e' il type def per le string
typedef basic_string<char, char_traits<char>, allocator<char> > string;
come vedi il primo argomento template e un char.
la insert e' definita nel seguente modo:
_Myt& insert(size_type _P0, const _E *_S);
e come secondo parametro vuole un puntatore const a _E ( che sarebbe il
primo template
di basic_string) cioe' alla fine vuole un const char * e 'X' non lo
e'....... mentre "X" si
(magic number).
-- 
Posted from [194.214.173.28] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 Der* objder = dynamic_cast<Der*>(new Base);
Ma questo funziona davvero?  Ne dubito...   dynamic_cast restituisce 0
se il puntatore castato non e' di tipo derivato.  Quello che funziona
e'
Base *p;
...
Derived *q = dynamic_cast<Derived *>(p);
// a questo punto q=0 se p non puntava ad un Derived, q!=0 altrimenti
<codice non testato>
-- 
Maurizio Loreti                         
http://www.pd.infn.it/~loreti/mlo.html
Univ. of Padova, Dept. of Physics - Padova, Italy            
lor...@pd.infn.it
Q: Why do programmers always mix up Christmas and Halloween?
A: Because 25 Dec = 31 Oct


Perche' 'X' e' un const char, "X" e' invece un const char*

 e'
Hai letto tutto quello che ho scritto ?


 Hai letto tutto quello che ho scritto ?
Si.  Tu hai letto quello che ho scritto io?  Il tuo codice produce
sempre un NULL pointer, quindi non fa quello che tu credi faccia,
quindi e' sbagliato.  Provare per credere:
MLO@mlinux 6 $ cat foo.cxx
#include <iostream>
struct Base { virtual ~Base(){} };
struct Derived : public Base { ~Derived(){} };
int main() {
  Derived *p = dynamic_cast<Derived *>(new Base);
  std::cout << "p = " << p << std::endl;
}
MLO@mlinux 7 $ g++ -ansi -Wall -o foo foo.cxx && ./foo
p = (nil)
MLO@mlinux 8 $


 quindi e' sbagliato.  Provare per credere:
In fatti io ho scritto (magari se lo rileggi lo trovi anche tu)
[...]
 In questo caso objder sara' sempre un puntatore nullo perche' in realta'
"new Base" e' un puntatore ad una classe Base. Di solito il dynamic_cast si
usa se sei
sicuro (o sospetti) che un puntatore a classe Base punti ad una derivata:
Base* pBase = new Der;
a questo punto puoi fare tranquillamente:
Der* pDer = dynamic_cast<Der*>(pBase);
[...]
nota che ho detto puntatore nullo non NULL pointer, cosa e' NULL ?


Scusate, mi č sorto un dubbio.
L'istruzione che il compilatore non accetta č del tipo;
der* der_ptr;
int main () {
    der = new base;
Ma in questo caso non sta avvenendo l'opposto, cioč prima der_ptr punta a
Der e poi si assegna l'indirizzo di Base.
Quindi ciň che non č ammesso č la conversione da Der* a Base*!
Aspetto risposte!.
Grazie

 Quindi ciò che non è ammesso è la conversione da Der* a Base*!
Quello che ti deve essere chiaro e' che una class derivata contiene tutte le
variabili della classe base, ma puo' contenerne altre. Quindi chiamando
un metodo della classe derivata (con un puntatore dichiarato puntatore
alla derivata, ma puntante alla base) si può andare a leggere/scrivere
su un'area di memoria che non è stata allocata dal costruttore della base,
cioe' puoi sovrascrivere su altre variabili o fare un accesso a memoria
che non appartiene al tuo processo. Per questo motivo il C++ mette a
disposizione il dynamic_cast che ti permette di verificare se sai cosa
stai facendo.
esempio:
#include <iostream>
using namespace std;
struct Base
{
    virtual ~Base() {}
    void ciao() { cout << "ciao dalla base" << endl; }
};
struct Der : Base
{
   Der() : m_Ciao("ciao dalla derivata"){}
   ~Der(){}
   void ciao() { cout << m_Ciao << endl; }
   string m_Ciao;
};
int main()
{
// caso OK
 Der     der;
 Base* pBase = &der; // da derivata a base
 Der*   pDer = dynamic_cast<Der*>(pBase); // da base a derivata: ammesso
 pBase->ciao();
 pDer->ciao();
// caso KO
 Base base;
 pDer = dynamic_cast<Der*>(&base); // ammesso, ma non concesso -> pDer = 0
 // altrimenti chiamando pDer->ciao() useresti il metodo della derivata che
 // accede a m_Ciao che non esiste xe' l'oggetto creato e' Base.
 // xo' se proprio vuoi puoi scrivere
 pDer = (Der *) &base;
 // pure questo e' ammesso e viene pure concesso.
 // se vuoi vedere qual e' il pericolo scommenta la riga successiva
 // pDer->ciao();
 return 0;
}
ciao
Massimo

  Der*   pDer = dynamic_cast<Der*>(pBase); // da base a derivata: ammesso
ma anche senza cast (Der* pDer) pDer non punta già a Der*?
ciao


ciao
Massimo

 effettuo una conversione. Io la vedo cosi'.
Si, ma da base a derivata e non viceversa.
Base* pBase = &der
equivale a
Base* pBase;  // a Base
pBase = &der // da Base a Der.
Anche se perņ il compilatore quando gli do un'istruzione simile:
class Base {
 };
class Der : public Base {
 };
Der* der = new Base; // Impossibile convertire da Base* a Der* anche se a me
sembra che da Der* si stia passando a  Base*
In definitiva č giusto come dici tu che per fare da Base* a Der* ci vuole il
cast etc... ma forse č che interpreto male la sintassi C++. (Vedi righe
sopra).
Ciao
Luigi

 pBase = &der // da Base a Der.
pBase e' sempre di tipo  Base*  (in C++ le variabili non possono
cambiare tipo), ma adesso ha un valore utile, e punta a der.
Il fatto che der in realta` sia di tipo Der non fa differenza
(la fara` solo chiamando metodi virtuali o usando la RTTI).
	Mauro

 non compilare).
Io l'avevo suddiviso per rendere l'idea della cronologia degli eventi cioè:
Base* pBase; // pBase punta a Base... e forse è stato questo il problema
perché pBase è solo di tipo Base* ma non punta ancora a niente.
pBase = &der; // faccio puntare pBase a Der.... per questo dicevo che la
conversione era da Base* a Der* quando invece si deve "leggere" alla
giapponese :)
assegno un Der* a un Base* quindi converto da Der* a Base*
/* Considerazione */
E cmq è giusto che sia così perchè una classe Der che deriva da Base ha
tutto ciò che è in Base + altre cose, quindi un Der* ha le caratteristiche
per diventare un Base* senza cast espliciti. E in virtù dello stesso
principio (cioè Der è più "aggiornata" di Base) un Base* avrebbe difficoltà
a diventare un Der*, che quindi ha bisogno di un cast.
/* Esatta? */
Ciao
Luigi