Newsgroup: it.comp.lang.c++
Titolo: vector e virtual

ho un vector che contiene oggetti che ereditano da una classe base. Ho ridotto il problema all'osso:
#include <iostream>
#include <vector>
class X {
public:
    bool operator()(){std::cout << "SONO X" << std::endl;};
};
class A : public X {
public:
    bool operator()() {std::cout << "SONO A" << std::endl;};
};
class B : public X {
public:
    bool operator()() {std::cout << "SONO B" << std::endl;};
};
int main()
{
    std::vector<X> vec;
    A a;
    B b;
    vec.push_back(a);vec.push_back(b);
    for (std::vector<X>::iterator i= vec.begin();
	 i!=vec.end();++i)
	(*i)();
    return 0;
}
e restituisce
SONO X
SONO X
che non è quello che voglio. Immagino bisogni dichiarare la classe X pure virtual, ma in questo caso il vector sarebbe un vector di puntatori:  vector<X*>, cosa che eviterei. Non sono molto esperto di funzioni virtual, chiedo lumi.

 }
Una soluzione sarebbe fare un vector<X*>.
E.

 chiedo lumi.
Sei vincolato all'operatore () o può essere sostituito da una funzione? 
Perchè vuoi evitare vector<X*> ? 
-- 
Salvatore

?manu* wrote:

infatti, è quello che ho fatto, però non mi piace usare i puntatori, volevo evitarlo:
#include <iostream>
#include <vector>
class X {
public:
    void virtual operator()()=0;
};
class A : public X {
public:
    void operator()() {std::cout << "SONO A" << std::endl;};
};
class B : public X {
public:
    void operator()() {std::cout << "SONO B" << std::endl;};
};
int main()
{
    std::vector<X*> vec;
    A *a = new A;
    B *b = new B;
    vec.push_back(a);vec.push_back(b);
    for (std::vector<X*>::iterator i= vec.begin();
         i!=vec.end();++i)
        (**i)();
    return 0;
}

infatti, è quello che ho fatto, però non mi piace usare i puntatori, volevo evitarlo:
Se vuoi sfruttare il polimorfismo non puoi fare a meno dei puntatori o
dei reference. Funziona solo quando ci sono di mezzo loro.

     vec.push_back(a);vec.push_back(b);
Non è solo una questione di vector, è un principio fondamentale nel C++: non
puoi mettere un A o un B dentro allo spazio destinato a un X (cioè alla
classe madre).
Poni che X contenga un int. Se A in aggiunta ne definisce un'altro, come
faccio a far stare A nello stesso spazio di memoria dove sta un X?
A a;
X x = a;
Facendo x = a, ottengo uno slicing del tipo figlio nel tipo madre: i dati
comuni vengono copiati, gli altri definiti da A vengono buttati via. È
un'operazione legittima, e il compilatore al massimo può dare un
avvertimento o nemmeno quello.
http://www.cs.ualberta.ca/~hoover/Courses/201/201-New-Notes/lectures/section/slice.htm
Per usare il polimorfismo *devi* usare o puntatori o riferimenti:
X* x = &a;
X& x = a;
ovviamente, non potendo avere un vettore di riferimenti, devi avere un
vettore di puntatori; direi che non si scappa.
vector<X*> v;
Ciao,
-Federico

Salvatore wrote:

sono vincolato all'operatore() perché devono essere classi funzione. Voglio evitare i puntatori per non complicarmi la vita.

Andrea Laforgia wrote:

avevo provato ad usare i reference al posto dei puntatori, ma non si possono fare vector di reference (o sì?)

 possono fare vector di reference (o sì?)
No. I container della libreria standard contengono oggetti concreti di un
determinato tipo. Se vuoi il polimorfismo, da qualche parte dovrai usare
dei puntatori. Se hai una libreria standard aggiornata alla TR1 (o se hai
Boost) puoi semplificarti la vita usando shared_ptr, magari usando un
wrapper. Ad esempio:
 
 struct X_wrap
 {
        std::tr1::shared_ptr<X> p;
 
        template< class D >
         X_wrap( const D& v ) : p ( new D(v) ) { }
        bool operator()() { return (*p)(); }
 };
 int main()
 {
        std::vector<X_wrap> v;
        v.push_back( A() );
        v.push_back( B() );
        cerr <<v[0]() << endl;
        cerr <<v[1]() << endl;
 }
Max

 }
Occhio che non stai deallocando lo spazio per A e per B. In un vero 
progetto devi ricordardi di chiamare delete esplicitamente sugli 
elementi dell'array. Oppure devi utilizzare degli SmartPointer di 
qualche tipo.
E.

?manu* wrote:

ma quando il vector si ditrugge (a fine programma) non chiama il distruttore dei suoi elementi?

 ma quando il vector si ditrugge (a fine programma) non chiama il 
 > distruttore dei suoi elementi?
Certo. Ma i tuoi elementi sono puntatori, che sono oggetti il cui 
distruttore non fa nulla. Per questo la soluzione migliore è quella di 
creare un oggetto con cui rimpiazzare i puntatori.
E.