Newsgroup: it.comp.lang.c++
Titolo: Metodi virtual in classi modello

Nel tentativo di trovare una soluzione brillante (ovvero semplice e 
funzionale), sono incappato in questo dubbio: se io ho un modello di 
classe, che contiene dei metodi virtuali, una chiamata ad uno di viene 
automaticamente risolta alla corretta specializzazione?
 
Esempio:
 
     template <class A> class CVirt
     {
       virtual void Inizializza()
       {
         data = 0;
       };
       private:
       A data;
     }
 
...
 
     main()
     {
       class CVirt <int> *iVirt;
       iVirt = reinterpret_cast<CVirt<int>new CVirt<double>;
       iVirt->Inizializza();
     }
 
PS: Tutto questo perché vorrei implementare una collezione (array/lista) 
di oggetti che hanno una struttura comune, ma che possono contenere dati 
di tipo diverso (vedi 'data' che può essere, ad esempio, int, double, 
ecc...)
 
 
-- 
Mickey
 
 


Perchè reinventare la ruota quando esiste la libreria std ?
 
 

 double, ecc...)
 
 
per carità degli dèi, c'è la standard template library che
per giunta mi pare faccia ora parte dello standard del
linguaggio. E' scritta da veri manici e a quanto ne so,
per fare (poco) di meglio ci vuole veramente molto.
 
 
-- 
Computer multitasking: oggetto che
può essere messo fuori uso da più
persone contemporaneamente.
 

 Perchè reinventare la ruota quando esiste la libreria std ?
 
Il 17/01/2012 22:19, Archaeopteryx ha scritto:
 > Il 17/01/2012 12:19, Mickey ha scritto:
 > per carità degli dèi, c'è la standard template library che
 > per giunta mi pare faccia ora parte dello standard del
 > linguaggio. E' scritta da veri manici e a quanto ne so,
 > per fare (poco) di meglio ci vuole veramente molto.
 
Voi avreste pure ragione. Il mio problema è che ho parecchia esperienza 
con il C, ed ho pure studiato bene la sintassi del C++, che però ho 
sempre usato con le MFC. Il risultato è un codice strutturato ad 
oggetti, disseminato di chiamate di libreria del C (sprintf, memcpy, 
ecc...).
 
Dovrò rassegnarmi a riprendere a studiare... :-)
 
Non è che poteste anche darmi un'idea di cosa usare delle stl per 
gestire una collezione di oggetti di classi diverse?
 
Grazie
 
-- 
Mickey

 
 
Basta che gli oggetti che vuoi collezionare derivino tutti dalla stessa
classe. Esempio:
 
    class MyType {
        public:
            virtual my_method () = 0;
    };
 
    // I vari tipi che voglio memorizzare saranno obbligati ad
    // implementare my_method in quanto `pure virtual`
    class A : public MyType { ... };
    class B : public MyType { ... };
    class C : public MyType { ... };
 
    // Qui ovviamente puoi usare liste, code, quel che ti pare
    std::vector<MyType *> items(10);
 
    // Popoli il tuo bel vettore
    items[0] = new A (...);
    items[1] = new B (...);
    ...
    items[9] = new C (...);
 
    // Quì uso `auto` come tipo: ocio che è legale solo per il C++0x
    for (auto i = items.begin(); i != items.end(); i ++) {
        MyType *x = *i;
        x->my_method();
    }
 
Facci sapere :)


 classe.
 
In effetti è stata la mia prima idea, salvo per il fatto che ho usato la 
CArray delle MFC invece che il vettore delle stl.
Il problema (che non è un problema funzionale, ma solo di stile) stà 
nell'implementazione dei singoli oggetti. Se volete entro nello 
specifico (chi non è interessato può smettere di leggere qui).
 
Sto implementando un protocollo di comunicazione su socket, che prevede 
diversi tipi di "messaggio". Ogni messaggio ha un intestazione comune, 
da cui si ricava, ad esempio, il tipo del messaggio e la lunghezza. 
Seguono poi una serie di informazioni che dipendono dal tipo di messaggio.
In C il metodo tipicamente utilizzato è quello di crearsi diverse 
strutture, una per ogni tipo di messaggio, con la prima parte identica 
per tutti (intestazione). Dopodiché in base al tipo di messaggio si fa 
il cast alla struttura opportuna.
 
struct msg_hdr {
int id;
int len;
};
 
struct msg1{
struct msg_hdr hdr;
int dato1;
};
 
struct msg2{
struct msg_hdr hdr;
double dato2;
};
 
ecc...
 
Nel codice:
 
struct msg_hdr *msg;
 
...
 
switch(msg->
hdr.id
) {
case 1:
   Elabora1((struct msg1*)msg);
   break;
case 2:
   Elabora2((struct msg2*)msg);
   break;
...
}
 
L'idea mia, in C++, è di crearmi una classe con un membro 'struct 
msg_hdr', e derivare da essa delle classi con delle strutture specifiche 
per ogni tipo di messaggio.
Gli oggetti di queste classi (o meglio: i loro indirizzi), infine, 
andranno collezionati un un CArray, e una volta estratti, di tali 
indirizzi verrà fatto il cast alla classe opportuna.
 
Così su due piedi mi sembra un po' troppo alla C-style. Mi domandavo se 
non esiste un metodo più oop-compliant.
 
Michele

 gestire una collezione di oggetti di classi diverse?
 
vector, deque, map, set, ...
 
C'e' solo l'imbarazzo della scelta.
 
  bye
	av.

 teorico.
Concordo in pieno!
 
Ho lavorato in intensamente in C (con le Windosw SDK) per parecchi anni 
(7 mi pare). Quando ho lasciato il posto di lavoro si stava passando al 
C++, ma il rischio e la tendenza della ventina di programmatori presenti 
era di rinominare in '.cpp' l'estensione dei sorgenti c (faccio per dire).
Nella nuova ditta lavoravano già con le MFC, ma anche lì ero io il più 
ferrato in oop, pur con tutti i miei limiti. Ed è per questo che sto 
cercando evoluzione lungo la retta via: se C++ dev'essere, che non sia 
C+- (leggi: C più o meno :-D ).
 
Butto lì un esempio, come domanda ai più esperti: spesso uso memcpy per 
azzerare intere strutture.
 
struct qualcosa {
...
} qlc;
memcpy(&qlc),0,sizeof(qlc));
 
Cosa si può utilizzare in C++, che non sia l'assegnamento a 0 dei 
singoli campi?
 
Vado ad inuito, e particolarizzo la domanda: esiste una sintassi per 
dire al costruttore di mettere a 0 tutti i campi (numerici)?
 
-- 
Mickey

 dire al costruttore di mettere a 0 tutti i campi (numerici)?
 
In generale le strutture dati parametrizzate da template usano come
default value quello del metodo costruttore di default (quello senza
parametri). In alcuni casi puoi fornire tu un valore di default. Per
esempio nelle liste[1]:
 
    explicit list ( size_type n, const T& value = T(), const Allocator& = Allocator() );
 
Puoi fornire come secondo parametro un valore del tipo scelto da template,
e di default diventa il valore dato dal default-constructor.
 
 
Per quanto riguarda memcpy, è tendenzialmente buona norma in C++ evitare
l'uso di `void *` ed utilizzare un'algoritmo template invece. Ecco dunque
che esiste l'header standard <algorithm>. Al posto di memcpy usi
std::copy[2] a cui passi (1) l'iteratore di inizio, (2) l'iteratore di
fine e (3) l'iteratore di destinazione.
 
Allo stesso modo la bzero e la memset vengono sostituite da std::fill[3],
per cui puoi fare cose come:
 
    int array[40];
    // fill with 0:
    std::fill(array, array + 40, 0);
 
    // ----
 
    MyClass array[30];
    MyClass default_value (my, parameters, here);
 
    // fill with default_value
    std::fill(array, array + 30, default_value);
 
    //why not with a vector?
    std::vector<MyClass> V (30);
    std::fill(V.begin(), V.end(), default_value);
 
 
REFERENCES:
[1] 
http://cplusplus.com/reference/stl/list/list/http://cplusplus.com/reference/stl/list/list/
 
[2] 
http://cplusplus.com/reference/algorithm/copy/
 
[3] 
http://cplusplus.com/reference/algorithm/fill/
 



 
i membri di una di uno oggetto (di classe o struct non c'è differenza) 
se l' inizializzazione non è specificata vengono automaticamente 
inizializzati usando il costruttore di default
 

 inizializzati usando il costruttore di default
Questo è chiaro.
Ma se io ho una serie numerosa di membri "int", devo per forza metterli 
a 0 uno alla volta nel costruttore. Mi chiedevo se non esistesse 
qualcosa di differente.
 
-- 
Mickey

 qualcosa di differente.
 
Dipende da quello che intendi per "serie numerosa".
Se utilizzi un array statico non puoi (Esempio 1). Se utilizzi un array
della standard library puoi fornire un valore di default, come scrivevo
qualche post fa (Esempio 2).
 
 
Esempio 1:
 
    #include <algorithm>
    #include <iostream>
    #include <vector>
 
    // procedura generica per stampare un vettore
    template <typename T>
    void print (T V, size_t n)
    {
        std::cout << "BEGIN" << std::endl;
        for (int i = 0; i < n; i ++) {
            std::cout << '(' << i << ',' << V[i] << ')' << std::endl;
        }
        std::cout << "END" << std::endl;
    }
 
    const size_t N = 10;
 
    int main ()
    {
        // Il vettore di int
        int V[N];
        // Lo riempio con dei 3
        std::fill(V, V + N, 3);
        // Lo stampo
        print(V, N);
 
        // Oppure un vettore di int della stl
        std::vector<int> W(N);
        // Ci copio dentro il vettore di prima
        std::copy(V, V + N, W.begin());
        // Lo stampo
        print(W, N);
 
        return 0;
    }
 
Esempio 2:
 
    #include <algorithm>
    #include <iostream>
    #include <vector>
 
    // Stessa procedura di prima (non l'ho toccata)
    template <typename T>
    void print (T V, size_t n)
    {
        std::cout << "BEGIN" << std::endl;
        for (int i = 0; i < n; i ++) {
            std::cout << '(' << i << ',' << V[i] << ')' << std::endl;
        }
        std::cout << "END" << std::endl;
    }
 
    const size_t N = 10;
 
    int main ()
    {
        // Inizializzo al valore di default 9
        std::vector<int> W(N, 9);
        // Lo stampo
        print(W, N);
 
        return 0;


 Se utilizzi un array statico non puoi (Esempio 1).
 
cmq per oggetti globali e static, l'inizializzazione 
predefinita è azzeramento e pulizia totale. I membri 
automatici e sullo heap invece non sono sicuro che 
garantiscano alcunché.
 
Per l'OP, se proprio hai una tremenda necessità di 
efficienza di inizializzare a zero, potresti prendere in 
considerazione di usare l'operatore NEW with PLACEMENT.
 
Allochi un unico grosso blocco, lo azzeri in un colpo con 
memzeroinit o roba simile (o allochi ram STATICA che è 
pulita all'avvio) e poi costruisci i tuoi oggetti nell'array 
col placement ... ti devi però smazzare tu a fornire offset 
aggiornati per non costruire più oggetti in sovrapposizione. 
Morale della favola, ci penserei diecimila volte se la 
necessità è solo l'azzeramento.
ciao
Soviet
 
 
ciao
Soviet


 considerazione di usare l'operatore NEW with PLACEMENT.
 
In caso di emergenza si, ma… mh! Pessima pratica!
 
Una cosa del genere è da considerarsi "di basso livello". Personalmente
l'ho usata solo una volta, interfacciando Erlang al C++ e passando per
un'allocazione di memoria fatta dal runtime di Erlang. Funzionava, ma mi
sono sentito sporco dentro.



Non serve metterli a zero; i membri di una classe vengono 
automaticamente inizializzati quando viene creato l' oggetto
chiamando l' apposito costruttore di default
(per ogni tipo T, anche semplice viene invocato il costruttore T())