Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 14
  1. #1
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826

    [c++]Templates , factory e base object

    ciao.
    Sto implementando un progetto con la programmazione generica e devo creare una object factory per un mio progetto in particolare per implementare la serializzazione/deserializzazione dei documenti.

    Mi ricordo che una delle prime cose che ho letto sui templates era relativa alle differenze tra le gerarchie di derivazione(ad es fare derivare tutti gli oggetti da un tipo base comune CObject) e la programmazione generica.

    In particolare puo fare molto comodo, se non è addirittura indispensabile , fare derivare tutti gli oggetti del mio progetto da un tipo base CObject.
    per es in una semplice factory per ogni classe ho una funzione CreateXXX e una funzione register, la funzione regiter inserisce in una mappa il puntatore alla funzione di creazione , con come chiave il nome della classe(Un RTTI dei poveri, una stringa o un id).

    Ora : se derivo tutti gli oggetti del mio progetto da una classe base CObject posso dichiarare il value della mappa(il puntatore a funzione) in cui si registrano tutte le classi con un tipo di ritorno CObject.
    Come fare altrimenti?

    La classe CObject dovrebbe contenere poche funzioni comuni per mantenere i miei oggetti "leggeri" , ma in questo caso se non uso questa gerarchia come si puo fare?

    chiramente questa derivazione non riguarderà le classi templates , ma le classi di dati o che contengono dati, l'instanziazione delle classi template pendo che dovrà essere hard coded nel codice con il relativo tipo(tra minore-maggiore per intenderci) .

    grazie.

  2. #2
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    anche se adesso che ci penso, mi viene un dubbio :
    Utilizzo per serializzare una classe stream che si occupa di svariate cose, scorro tutti gli oggetti di tipo base CObject e chiamo il metodo save passando lo stream, nei CObject implemento il metodo save salvando le variabili da serializzare puntatori e dati.
    ma se serializzo tutte le variabili membro della classe e i suoi collegamenti, la funzione che crea la classe dovrebbe essere new item<int> e non new item<double> per es.

    ma si puo fare?
    come?

    ps.non posso usare boost e le sue classi di serializzazione.

  3. #3
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    allora in pratica la domanda era:
    è possibile serializzare un template?
    la risposta da quello che ho capito è no(felicissimo di essere smentito).
    Ed essendo i template un meccanismo compile time, cioè creato dal client ho pensato che è anche giusto cosi.

    Posso pero' creare nel codice le definizioni dei tipi e passare ad essi i dati deserializzati.
    ad es:
    codice:
       class CEntity
       {
       
           CData<int> CDataInt;
           CData<string> CDataStr;
          Save(stream* pArchive)
           {
               pArchive->SetDataToStream(CDataInt));
               pArchive->SetDataToStream(CDataStr));
    
            }  
    
           Load(stream* pArchive)
           {
               CDataInt.setData(pArchive->GetDataFromStream());
               CDataStr.setData(pArchive->GetDataFromStream());
    
            }  
        }
    e poi posso creare 24234234234 oggetti CEntity o/e salvarli/caricarli da file.
    Forse posso procedere cosi senza entrare nei dettagli della serializzazione/deserializzazione.
    Sulle domande della derivazione da CObject non ho trovato pero' ancora risposte.
    ciao

  4. #4
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Originariamente inviato da giuseppe500
    allora in pratica la domanda era:
    è possibile serializzare un template?
    Risposta breve: dipende.
    Risposta lunga: i dati del template sono serializzabili?
    CData<> ha una funzione che consente di trasformare il dato in una sequenza di byte e trasformare una sequenza di byte nel dato?
    Per inciso, il fatto che la classe sia un template non significa nulla. Lo stesso problema lo hai in una classe normale.

    Sulle domande della derivazione da CObject non ho trovato pero' ancora risposte.
    Come fare altrimenti, cosa? Non è molto chiara la domanda.
    Vuoi usare una factory per tutto?
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  5. #5
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    allora, mi spiego meglio:
    Ho visto in uno o due progetti open source di dimensioni puttosto grandi questo meccanismo per la serializzazione:
    1)ogni classe a cui voglio applicare la serializzazione/deserializzazione deriva da un oggetto base CBaseObject per es.
    2)ogni classe ha una funzione
    codice:
    CBaseObject CClasseX::Create()
    {
        return new CClasseX()
    }
    3)durante il pre main(in un progetto è documentata cosi' la parte del programma che precede la funzione main) ogni classe registra l'indirizzo della propria funzione Create in una mappa con una chiave: L'RTTI.name() e valore puntatore a funzione con tipo di ritorno CBaseObject
    codice:
    typedef CBaseObject * (*FactoryFunction)(InStream& stream);
    typedef std::map<std::string, FactoryFunction> FactoryMap;
    ora , quando serializzo scrivo sul file un identificativo (il nome RTTI della classe) in modo che quando deserializzo
    1)leggo questo nome
    2)estraggo la funzione che ha come chiave questo nome
    3)lancio la funzione che mi ritorna l'oggetto non inizializzato ma del tipo corretto.

    ma come fare questo se la classe è una classe template?
    1)che tipo di ritorno generalizzato utilizzare per la funzione di creazione nella mappa di una classe template
    2)come implementare la funzione create?

    codice:
    template <class T>
    ??? CClasseX::Create()
    {
        return new CClasseX<T>()
    }
    è un po shodan che mi viene in mente questo problema, probabilmente causato da un modello mentale che uso sbagliato per rappresentare i template:
    Il tipo generico è come se "legasse in qualche modo il template"(dall' inizializzazione della classe template in poi) da quando il tipo della classe template è concreto , le classi template mi appaiono diverse dalle classi normali (e probabilmente è giusto) ma non riesco a staccarmi dal concetto di classe base e derivazione,
    e questa era una domanda : come vedi ereditare il template da una classe base che implementi varie funzionalità base?
    vabbe forse sono andato un po OT.

    Risposta lunga: i dati del template sono serializzabili?
    si i dati del template sono serializzabili, mettiamo che ho un buffer di tipo int

    codice:
    template<class T>
    CData<int>
    {
        T* m_data = new T[10];
    }
    .
    .
    grazie.

  6. #6
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Il tipo generico è come se "legasse in qualche modo il template"(dall' inizializzazione della classe template in poi)
    In effetti è così. Quando una classe template è istanziata il tipo di dato si fonde con il nome.
    Ad esempio se hai la classe CClasseX<T>, quando il template è istanziato il compilatore può scrivere nel codice reale (non è detto che scriva proprio questo, ma concettualmente si):
    codice:
    CClasseX_int {}
    CClasseX_double {}
    Che sono due classi che non hanno niente a che vedere le une con le altre.
    Ne consegue che anche la funzione Create() delle classi concrete non hanno niente a che vedere le une con le altre perché restituirebbero puntatori a classi diverse.
    Dato che le funzioni di creazione vengono inserite in un container, la conseguenza è che non è possibile parametrizzare il tipo di ritorno della funzione (il codice non compilerebbe proprio), ma è indispensabile sganciare il tipo di ritorno dal parametro template.
    I modi sono essenzialmente due: void* o una classe base non parametrica.
    void* si deve scartare a priori perché, come minimo, non si porta dietro informazioni sul tipo reale istanziato. Resta la classe base non parametrica, cioè la tua CBaseObject.

    1) Se si vuole un tipo di ritorno comune per una serie di template serve una classe base non template.

    Detto questo, sorge un problema. Le funzioni di una classe template che si basano sul parametro template non possono essere virtual (il compilatore non può sapere su quanti tipi verranno concretizzati i template).

    2) Possono essere virtual solo le funzioni che non si basano sul parametro template.

    Se occorre usare una di queste funzioni basate sul parametro template occorre effettuare il downcast da puntatore base a puntatore concreto e qui l'unico aiuto è la RTTI del compilatore.

    come vedi ereditare il template da una classe base che implementi varie funzionalità base?
    Dipende da cosa sono queste funzionalità base. In generale la vedo come un metodo potente per determinati problemi.
    Il modo corretto di risolvere determinati problemi.
    Osserva la tua classe CEntity.
    Hai due CData che sono istanziati con due tipi diversi, un int e una string.
    Poi passi questi dati a una funzione SetDataToStream.
    I casi sono tre:
    1) questa funzione è in overloading su ogni possibile istanza di CData<T>
    2) questa funzione è una member template di stream
    3) questa funzione accetta una classe base da cui deriva CData<T>

    La 1 comporta una scrittura manuale di codice per ogni tipo possibile di CData e questo è inaccettabile.
    La 2 comporta che il compilatore istanzi il codice corretto della funzione basandosi su ciò che gli arriva come parametro. Questo vuol dire che il compilatore genera tante SetDataToStream quanti sono i parametri diversi che gli arrivano, ma gestisce lui la cosa quindi fatica in meno per chi scrive codice.
    La 3 comporta una singola istanza di SetDataToStream dato che il parametro è di un solo tipo, ma richiede che il dato sia polimorfico.
    Non è detto che la 2 sia migliore della 3 o viceversa.
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  7. #7
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    scusate.
    Il problema è risolvibile, come visto in altri software opensource serializzando tutti i tipi (di un array di struttura)in un tipo generico char(dei BYTE alla fine).

    Ho visto vari sorgenti per questo tipo di software(engine 3d)e tutti ad es per i buffer opengl(degli array di una struttura dati ) gestiscono si i vari tipi , ma alla fine memorizzano uno stream e gli offset tra gli elementi.

    Lo stesso opengl vuole tra i suoi parametri per creare un buffer uno stream o meglio: un cast a (void*) per il buffer che è composto da i piu svariati tipi.

    non vedo davvero altra soluzione, ad es: un vboManager<T> avra una funzione non template getDataStream che ritornerà uno stream di byte che serve per creare l'oggetto vero e proprio opengl(vbo = un vertexbuffer)e questo puo essere serializzato , quello che conta è memorizzare anche gli offset tra i tipi e i size dei tipi, poi si puo benissimo ricreare il vbo dopo la deserializzazione dei dati.

    ad es:
    codice:
    struct vertexbuffer{
        float     x,y,z//punti
        float     nx,ny,nz//normali
        int        i1,i2,i3//idxbones nella skeleton animtion
    
    }
    template<class T>
    class vboManager
    {
        T* data = new T[500]//500 elementi ciascuno con 3 punti , 3 normali e 3 indici bones
    }
    
    vboManager<vertexbuffer> vbo;
    
    vbo.data[0].x =1.0;
    vbo.data[0].y =1.0;
    
    vbo.data[499].x =1.0;
    vbo.data[499].y =0.7;
    ecc...
    poi creo il vertex vbuffer e trasformo data in uno stream di bytes
    vedete soluzioni migliori?
    grazie.

  8. #8
    evidentemente non ho compreso bene il problema. La soluzione di shodan non va bene? una cosa del genere:
    codice:
    CObject* Factory::CreateObject(const serializedObj& obj) {
        string objType = obj.getType();
        CObject* ret;
        // RTTI
       // creatorMap<string, CObject* (*create)()>
        ret = CObject::creatorMap.find(objType).create();
        ret->fromSerializedObj(obj);
        return ret;
    }

  9. #9
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    ho capito , grazie.
    scusate.

  10. #10
    Niente scuse , il problema e` piuttosto complesso ed e` necessario analizzarlo per bene se non si vuole finire a scrivere codice inutile.

    Per esempio la mia soluzione ha un problema, ogni classe che che eredita da CObject deve registrare il suo metodo nella mappa. Stavo pensando ad una soluzione per fare questo in automatico.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.