Alcuni dubbi su come gestire una gerarchia di strutture dati e classi simile a quella riportata sotto (i dubbi sono nei commenti messi nel codice riportato):


codice:
enum Code: unsigned int {Type1, Type2};

struct BaseStruct
{
  //...
  Code getType() const = 0;
};

struct BaseStruct1: public BaseStruct
{
  //...
  Code getType() const override
  {
    return Type1;
  };
};

struct BaseStruct2: public BaseStruct
{
  //...
  Code getType() const override
  {
    return Type2;
  };
};


class Base
{
  public:
    //...metodi vari
    virtual void set(BaseStruct* data) = 0;
    virtual BaseStruct* get() const = 0;
    virtual Code getType() const = 0;
};

class Derived1: public Base
{
  public:
    //...metodi vari
    void set(BaseStruct* data) override
    {
      if(data)//verifico che data non sia un nullptr
      {
        if(data->getType() == Type1)//verifico che data sia del tipo corretto
        {
          BaseStruct1* temp = static_cast<BaseStruct1*>(data);
          //quello che serve per settare i dati membro
        }
        else
        {
          //se data e' puntatore valido ma di tipo scorretto, due opzioni
          //1 - lascio che non succeda niente
          //2 - eccezione
        }
      }
      else
      {
        //se arrivo qui, quindi data = nullptr, due opzioni
        //1 - lascio che non succeda niente
        //2 - eccezione
      }
    };
    BaseStruct* get() const override
    {
      BaseStruct* temp = nullptr;
      if(*this)//per fare questo devo aver implementato l'overload dell'operatore bool e quindi aver deciso i casi per cui restituisce true o false
      {
        temp = new BaseStruct1(/*passo quello che serve*/);
      }
      return temp;
    }
    Code getType() const override
    {
      return Type1;
    };
};

class Derived2: public Base
{
  public:
    //...metodi vari
    void set(BaseStruct* data) override
    {
      if(data)//verifico che data non sia un nullptr
      {
        if(data->getType() == Type2)//verifico che data sia del tipo corretto
        {
          BaseStruct2* temp = static_cast<BaseStruct2*>(data);
          //quello che serve per settare i dati membro
        }
        else
        {
          //se data e' puntatore valido ma di tipo scorretto, due opzioni
          //1 - lascio che non succeda niente
          //2 - eccezione
        }
      }
      else
      {
        //se arrivo qui, quindi data = nullptr, due opzioni
        //1 - lascio che non succeda niente
        //2 - eccezione
      }
    };
    BaseStruct* get() const override
    {
      BaseStruct* temp = nullptr;
      if(*this)//per fare questo devo aver implementato l'overload dell'operatore bool e quindi aver deciso i casi per cui restituisce true o false
      {
        temp = new BaseStruct2(/*passo quello che serve*/);
      }
      return temp;
    }
    Code getType() const override
    {
      return Type2;
    };
};

creo una classe Factory fatta in modo che crei il corretto oggetto derivato da Base

codice:
class Factory
{
  public:
    static Base* make(BaseStruct* data)
    {
      Base* temp = nullptr;
      if(data)
      {
        Code code = data->getType();
        switch (code)
        {
          case Type1:
            temp = makeDerived1(data);
            break;
          case Type2:
            temp = makeDerived2(data);
            break;
          default:
            break;
        };
      }
      return temp;
    };
  private:
    static Base* makeDerived1(BaseStruct* data);
    static Base* makeDerived2(BaseStruct* data);
};

creo poi una classe che funga da interfaccia per non dovermi preoccupare di che classe concreta derivata da base stia utilizzando.

codice:
class Interfaccia
{
  public:
    //...metodi vari
    Interfaccia(BaseStruct* data):mBase(Factory::make(data)){};//se data e' nullptr anche mBase contiene nullptr
    void set(BaseStruct* data)
    {
      if(mBase)//prima verifico che effettivamente mBase non sia nullptr, perche' potrei averlo creato cosi' per come e' implementato Factory::make
      {
        if(data)//verifico che data non sia un nullptr
        {
          if(data->getType() == mBase->getType())
          {
            mBase->set(data);
          }
        }
        else
        {
          //qui ho tre opzioni:
          //1 - faccio niente
          //2 - mBase.reset(Factory::make(data)); anche se mi sembra il comportamento che crea piu' difficolta di manutenzione, se voglio cambiare
          //    il tipo di mBase, allora e' forse meglio creare un metodo convert(BaseStruct* data) che svolge questo compito
          //3 - eccezione
        }
      }
      else
      {
        //tre opzioni
        //1 - faccio niente
        //2 - eccezione
        //3 - mBase.reset(Factory::make(data));
      }
    };
    BaseStruct* get() const
    {
      BaseStruct* temp = nullptr;
      if(mBase)
      {
        temp = mBase->get();
      }
      return temp;
    };
    Code getType()
    {
      if(mBase)
      {
        return mBase->getType();
      }
      else
      {
        //due opzioni
        //1 - nell'Enum Code aggiungo NoType ad esempio e restituisco questo valore
        //2 - eccezione
      }
    };
  private:
    std::unique_ptr<Base> mBase;
};


Cosi' su due piedi direi che probabilmente conviene mettere le eccezioni nella gerachia di classi e gestirle nei singoli metodi della classe interfaccia

quindi potrebbe diventare ad esempio

codice:
class Interfaccia
{
  public:
    //...metodi vari
    Interfaccia(BaseStruct* data):mBase(Factory::make(data)){};//se data e' nullptr anche mBase contiene nullptr
    void set(BaseStruct* data)
    {
      if(mBase)//prima verifico che effettivamente mBase non sia nullptr, perche' potrei averlo creato cosi' per come e' implementato Factory::make
      {
        if(data)//verifico che data non sia un nullptr
        {
          if(data->getType() == mBase->getType())
          {
            mBase->set(data);
          }
        }
        else
        {
          throw std::MyException("Eccezione");
        }
      }
      else
      {
        throw std::MyException("Altra eccezione");
      }
      catch (std::exception& e)
      {
        std::cerr << "exception: " << e.what() << '\n';
      }
    };
    BaseStruct* get() const
    {
      BaseStruct* temp = nullptr;
      if(mBase)
      {
        temp = mBase->get();
      }
      return temp;
    };
    Code getType()
    {
      if(mBase)
      {
        return mBase->getType();
      }
      else
      {
        //due opzioni
        //1 - nell'Enum Code aggiungo NoType ad esempio e restituisco questo valore
        //2 - eccezione
      }
    };
  private:
    std::unique_ptr<Base> mBase;
};
Qualche consiglio? Grazie