Visualizzazione dei risultati da 1 a 7 su 7
  1. #1
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177

    [C++] Puntatore come parametro passato

    Mi sto perdendo, o meglio, mi sono gia' perso, nei confronti dei puntatori passati come parametro a un metodo e il loro "significato".
    Ho creato una porzione di codice che dovrebbe simulare il mio problema.

    Ho una serie di classi derivate da Abstract, Derived1 e Derived2.

    Ho la necessita' di cambiare strada facendo la classe dell'oggetto istanziato, ho quindi creato una serie di classi derivate da AbstractConverter, che implementano un metodo convert che preso come parametro in input un puntatore a un oggetto di tipo Abstract, lo converte.

    Ora, compilato a casa per il problema specifico, no problem, ma si pianta runtime quando arrivato al metodo convert deve creare l'istanza del nuovo oggetto, dando un messaggio di errore del tipo che il costruttore richiamato e' di tipo virtuale... (vado a memoria, mi pare di ricordare che ieri sera mi desse un messaggio con questo significato).

    Il codice che ho postato sotto, che riproduce lo schema con cui ho strutturato il caso, compilato e fatto girare su questo sito http://cpp.sh/ va senza problemi.

    Dove sta il problema?

    Il dubbio che mi e' venuto e' che io passo il puntatore al metodo convert per valore, quindi le operazioni che faccio all'interno del metodo convert in realta' non mi stanno modificando l'oggetto che vorrei modificare, quindi in realta' dovrei passare il puntatore per riferimento, in modo da agire sull'oggetto che voglio modificare.

    Nel caso sotto rirpodotto probabilmente tutto fila liscio in quanto non devo convertire anche i dati membro dell'oggetto, mentre nel mio caso reale la conversione di classe e' dovuta a una "conversione di dati" da un sistema ad un altro.

    Ecco il codice che simula lo schema di implementazione da me utilizzato:

    codice:
    #include <iostream>
    #include <string>
    
    class Abstract
    {
      public:
        enum Type: unsigned int {Derived1,Derived2};
        virtual ~Abstract(){};
        virtual void hello()=0;
        virtual Abstract::Type getType()=0;
    };
    
    class Derived1: public Abstract
    {
      virtual void hello()
      {
        std::cout<<"\nHello from Derived1";
      };
      virtual Abstract::Type getType()
      {
        return Abstract::Derived1;
      };
    };
    
    class Derived2: public Abstract
    {
      virtual void hello()
      {
        std::cout<<"\nHello from Derived2";
      };
      virtual Abstract::Type getType()
      {
        return Abstract::Derived2;
      };
    };
    
    class AbstractConverter
    {
      public:
        enum Convert: unsigned int{ToDerived1,ToDerived2};
        virtual ~AbstractConverter(){};
        virtual void convert(Abstract* object_to_convert)=0;
    };
    
    class ConverterToDerived1: public AbstractConverter
    {
      public:
        virtual void convert(Abstract* object_to_convert)
      {
        switch(object_to_convert->getType())
        {
          case Abstract::Derived1:
            std::cout<<"\nE' gia' Derived1";
            break;
          case Abstract::Derived2:
            fromDerived2(object_to_convert);
            break;
        }
      };
      private:
      void fromDerived2(Abstract* object_to_convert)
      {
        delete(object_to_convert);
        object_to_convert=new Derived1();
      }
    };
    
    class ConverterToDerived2: public AbstractConverter
    {
      public:
        virtual void convert(Abstract* object_to_convert)
      {
        switch(object_to_convert->getType())
        {
          case Abstract::Derived1:
            fromDerived1(object_to_convert);
            break;
          case Abstract::Derived2:
            std::cout<<"\nE' gia' Derived2";
            break;
        }
      };
      private:
      void fromDerived1(Abstract* object_to_convert)
      {
        delete(object_to_convert);
        object_to_convert=new Derived2();
      }
    };
    
    int main()
    {
      Abstract* abstract=0;
      //prova del costruttore di Derived1
      abstract= new Derived1();
      std::cout<<"\nAbstract e' di tipo "<<abstract->getType();
      abstract->hello();
      delete(abstract);
      //prova del costruttore di Derived2
      abstract= new Derived2();
      std::cout<<"\nAbstract e' di tipo "<<abstract->getType();
      abstract->hello();
      AbstractConverter* converter=0;
      //ora provo il converter to Derived1
      converter= new ConverterToDerived1();
      //abstract ora è Derived2, tento la conversione a Derived1
      converter->convert(abstract);
      std::cout<<"\nAbstract e' di tipo "<<abstract->getType();
      abstract->hello();
      //abstract ora è Derived1, tento la conversione a Derived1
      converter->convert(abstract);
      std::cout<<"\nAbstract e' di tipo "<<abstract->getType();
      abstract->hello();
      delete(converter);
       //ora provo il converter to Derived2
      converter= new ConverterToDerived2();
      //abstract ora è Derived1, tento la conversione a Derived2
      converter->convert(abstract);
      std::cout<<"\nAbstract e' di tipo "<<abstract->getType();
      abstract->hello();
      //abstract ora è Derived2, tento la conversione a Derived2
      converter->convert(abstract);
      std::cout<<"\nAbstract e' di tipo "<<abstract->getType();
      abstract->hello();
      return 0;
    }

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Il problema del passaggio lo risolvi passando il puntatore per reference
    codice:
    void fromDerived2(Abstract*& object_to_convert)
      {
        delete(object_to_convert);
        object_to_convert=new Derived1();
      }
    ma onestamente non capisco il senso di distruggere un oggetto e ricrearlo da zero con parametri garbage filled.
    Ma che stai cercando di fare esattamente?
    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.

  3. #3
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177
    Il problema reale nasce dal voler rappresentare un punto geometrico, tenendo conto della possibilità che la sua posizione nello spazio possa essere espressa con diversi sistemi (coordinate cartesiane, polari, ecc), e con possibilità di passare da un sistema all'altro.

    Io ho organizzato così:

    classe astratta AbstractCoordinate da cui derivo i sistemi di coordinate (cartesiane2d, cartesian3D, polari,ecc), in cui implemento i metodi set, get, getType(mi da il tipo di coordinata), ecc.

    Classe Point, che ha come dato membro mCoordinate di tipo AbstractCoordinate*.
    La classe Point quindi richiama i metodi di mCoordinate per fare set, get.
    La classe Point inoltre implementa il metodo pubblico convert(/*tipo di destinazione*/) che serve ad effettuare la conversione da un tipo di coordinate ad un altro.
    codice:
    class Point
    {
      public:
        //costruttori vari
        //distruttore
        //metodi set, get, getType
        //metodo per la conversione delle coordinate
        void convert(AbstractCoordinateConverter::Converter convert_to);
        /* convert_to e' il  parametro che permette la scelta del nuovo tipo di coordinate*/
      private:
        AbstractCoordinate* mCoordinate;
    }
    Nella fattispecie il metodo convert di Point è fatto così

    codice:
    void convert(AbstractCoordinateConverter::Converter convert_to)
    {
      //creo l'oggetto converter
      AbstractCoordinateConverter* converter = CoordinateConverterFactory::makeCoordinateConverter(convert_to);
      //l'oggetto converter prende il dato membro e lo trasforma
      converter->convert(mCoordinate);
      //elimino l'oggetto converter
      delete(converter);
    }
    il problema della conversione è quindi delegato a un oggetto temporaneo converter, in cui il metodo convert è così implementato

    codice:
    //metodo convertitore implementato in una delle classi converter
    //prende come parametro un puntatore a un oggetto di tipo AbstractCoordinate*
    virtual void convert(AbstractCoordinate* coordinate)
    {
      switch(coordinate->getType())//lo switch è fatto prendendo come parametro di scelta il tipo di AbstractCoordinate realmente passato
      {
        case AbstractCoordinate::Cartesian:
          std::cout<<"\nE' gia' Cartesian\n";
          break;
        case AbstractCoordinate::Cartesian3D:
          fromCartesian3D(coordinate);//è il metodo privato dell'oggetto converter che implementa la conversione a partire da una coordinata di tipo Cartesian3D
          break;
        case AbstractCoordinate::Polar:
          fromPolar(coordinate);//è il metodo privato dell'oggetto converter che implementa la conversione a partire da una coordinata di tipo Polar
          break;
      }
    }
    riporto quindi l'implementazione del metodo fromCartesian3D(coordinate), l'altro è simile come concezione

    codice:
    void CoordinateConverterToCartesian::fromCartesian3D(AbstractCoordinate* coordinate)
    {
      //memorizzo in un vettore temporaneo i dati della coordinata di tipo 3D (x,y e z)
      std::vector<double> array_to_convert(coordinate->get());
      //elimino la z perche' in questo caso sto trasformando in cartesiano 2D, quindi solo x e y
      array_to_convert.pop_back();
      //cancello il coordinate esistente che è di tipo 3D
      delete(coordinate);
      coordinate=0;//questo è necessario o posso evitarlo
      //creo un nuovo oggetto di tipo cartesiano 2D dandogli in input i valori delle coordinate gia' opportunamente trasfromati
      coordinate = new CartesianCoordinate(array_to_convert);
    }
    avendo messo in ogni metodo da me creato una macro che stampa a video il nome della classe e il nome del metodo invocato, il progr si pianta quando è stato chiamato il costruttore del nuovo oggetto.

    Grazie.

  4. #4
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    il progr si pianta quando è stato chiamato il costruttore del nuovo oggetto.
    Cioè qui?
    codice:
    coordinate = new CartesianCoordinate(array_to_convert);
    Il problema mi sembra slegato al passaggio del puntatore, che come detto risolvi passando il puntatore per reference nelle funzioni che lo accettano come parametro.
    codice:
    virtual void AbstractCoordinateConverter::convert(AbstractCoordinate*& coordinate);
    void AbstractCoordinateConverter::fromCartesian3D(AbstractCoordinate*& coordinate);
    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 L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177
    Grazie delle risposte, il problema era legato proprio al passaggio per valore e non per indirizzo del puntatore.
    Ora ho provato a inserire & e tutto fila liscio.
    Non credo ci siano altri problemi subdoli legati al costruttore, in quanto testato da solo per i fatti suoi funziona.

    Quanto alla logica dell'implementazione può avere senso?
    In questo modo, posso aggiungere tipi di coordinate al punto, senza dover troppo impazzire.

    Grazie di nuovo

  6. #6
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    A mio avviso è un approccio pulito ed elegante. Chapeaux
    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 L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177
    Quote Originariamente inviata da shodan Visualizza il messaggio
    A mio avviso è un approccio pulito ed elegante. Chapeaux
    I complimenti fanno sempre piacere e ringrazio, ma la verità è che se il maestro è in gamba (vedi qui http://forum.html.it/forum/showthrea...1#post25332072 ) e l'allievo ha voglia di studiare e migliorarsi, i risultati prima o poi arrivano, anche se bisogna essere consci del fatto che in realtà non si sarà mai arrivati...l'indicazione dei Design Pattern e il loro studio mi ha fatto solo bene.

    P.S. del resto avrai notato che non ho ancora digerito gli smart pointer, ma ci arriveremo...

    Grazie di nuovo!

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.