Struct Werte indizieren



  • Hi Fans,

    ich habe z.B. folgendes Struct und eine Klasse definiert:

    *.h:
    
    struct SWerte
    {
           float fWert1;
           float fWert2;
           float fWert3;
    };
    
    class TestC
    {
          private:
    
          SWerte Werte;
    
          public:
    
          TestC();
          ~TestC();
    
          float GetStructValue(int iIndex);
    };
    
    *.cpp
    
    TestC::TestC()
    {
         Werte.fWert1 = 0.1;
         Werte.fWert2 = 0.2;
         Werte.fWert3 = 0.3;
    }
    
    TestC::~TestC()
    {
    }
    
    float TestC::GetStructValue(int iIndex)
    {
          float fRetVal = 0.0;
    
          switch (iIndex)
          {
                 case 0  : { fRetVal = Werte.fWert1; break; }
                 case 1  : { fRetVal = Werte.fWert2; break; }
                 case 2  : { fRetVal = Werte.fWert3; break; }
                 default : {}
          }
    
          return fRetVal;
    }
    

    Nun ist es ja so, dass wenn oben im Struct noch eine Variable dazu kommt, muß man unten in der Switch-Anweisung eine case-Zeile einfügen.

    Wie könnte man sowas automatisieren? Sprich, so, dass man sauber über den Index an das jeweilige Struct Element rankommt (quasi als foreach-Ersatz), trotzdem aber innerhalb der Klasse das Struct weiter verwendet (wegen der übersichtlicheren Namensgebung der einzelnen Structelemente).

    Es soll also ein cleverer Bezug zwischen Index des Structelementes von außen und Namen von innen (Klasse) bestehen.

    MfG F98.



  • Hallo,

    Wieso nimmst du in deiner struct nicht einfach ein Array (vector)?



  • Wie wärs mit einem Array?

    struct SWerte 
    { 
           float fWert[3]; 
    };
    
    //...
    
    float TestC::GetStructValue(int iIndex)
    {
        return fWert[iIndex];
    }
    

    Achja, Array-Indizes gehen von 0 bis Anzahl-1. Die Werte in diesem Beispiel heißen also fWert[0], fWert[1] und fWert[2].

    Gruß
    Don06



  • Ich hatte gerade auch das Problem, dass ich ein struct benötige
    für die interne Berechnung in der Klasse, weil da Indizes doof sind. Aber
    nach außen sollen die struct member über einen Index angesprochen werden.

    Was hälst du von folgender Lösung:

    float GetValueFromFloatStruct(int iID, float *FirstElement)
    {
        for (int i=0; i<iID; i++)   FirstElement++;
        return *FirstElement;
    }
    

    Parameter ist die ID des entrechendne Items und der Zeiger auf das erste Structelement. Vorraussetzung ist natürlich, dass es sich bei den struct membern nur um float Datentypen handelt.



  • und was ist jetzt hier der Unterschied zu einem Array, außer das du Pointerarithmetik verwendest?



  • Geht nicht sowas hier?

    union SWerte
    {
        struct
        {
            float fWert1;
            float fWert2;
            float fWert3;
        };
    
        float afWerte[3];
    };
    

    Ja, anonyme structs/unions sind nicht standardkonform ...
    Aber sonst sollte das zumindest für gewisse Compiler funktionieren 🤡



  • Also die union-Variante find ich ziemlich gut. Ist sauberer als das Herumhantieren mit Pointern.

    An Braunstein: Ich brauche das struct, weil ich intern gern mit Variablen arbeiten möchte und nach außen die einzelnen Elemente automatiert über einen Index auslesen möchte.



  • Der BC++B frißt sowas (anonyme Structs), steht auch in der Hilfe.

    Besser ist allerdings:

    *.h:
    
    #define MAXCOUNT 3
    
    union UWerte
    {
        struct SWerte
        {
            // hier dürfen MAXCOUNT float Variablen rein
            float fWert1;
            float fWert2;
            float fWert3;
        } stWerte;
    
        float afWerte[MAXCOUNT];
    
        UWerte()
        {
            for (int i=0; i<MAXCOUNT; i++)
            {
                afWerte[i] = 0.0;
            }
        };
    
        ~UWerte()
        {
        };
    };
    
    class TestC
    {
          private:
    
          UWerte Werte;
    
          public:
    
          TestC();
          ~TestC();
    
          float GetStructValue(int iIndex);
    };
    
    *.cpp
    
    TestC::TestC()
    {
         Werte.stWerte.fWert1 = 0.1;
         Werte.stWerte.fWert2 = 0.2;
         Werte.stWerte.fWert3 = 0.3;
    }
    
    TestC::~TestC()
    {
    }
    
    float TestC::GetStructValue(int iIndex)
    {
          float fRetVal = 0.0;
    
          if ((iIndex >= 0) && (iIndex <MAXCOUNT))
          {
             fRetVal = Werte.afWerte[iIndex];
          }
    
          return fRetVal;
    }
    


  • wusste garnicht dass es fuer unions Konstruktoren und Destruktoren gibt oO man lernt doch immer wieder neues.

    An Braunstein: Ich brauche das struct, weil ich intern gern mit Variablen arbeiten möchte und nach außen die einzelnen Elemente automatiert über einen Index auslesen möchte.

    Wo ist bei dir intern und nach aussen? Wenn du das Ding privtae machst, kannst du eh nur innerhalb der umgebenden Klasse damit arbeiten, und was anderes machst du auch nicht. Das einzige was ich bisher sehe, ist dass du das "Ding" in der einen Methode wie ein Array behandelst, in der anderen aber wie ein struct. Das macht in meinen Augen nur den Code unleserlich und schwer wartbar.
    Insofern: wenn du eh die meiste Zeit iterierst, dann bleib beim Array.
    Falls du allerdings nette Namen fuer die Werte brauchst und iterieren musst, dann fallen mir spontan 2 Wege ein:

    Variante a:

    struct SWerte {
    enum { PAPISGELD;
           MAMISGELD;
           OMISGELD;
           MAX;
         } 
    float w[MAX-1];
    } werte;
    
    //iteration
    for (int i = 0; i < SWerte::MAX; i++)
      cout << werte.w[i];
    
    //Zugriff mit Namen
    cout << "Papi hat " << werte.w[SWerte::PAPISGELD];
    

    Variante b (fuer ganz ganz seltene iterationen, naemlich unschoen!)

    struct SWerte {
      float papisgeld;
      float mamisgeld;
      float omisgeld;
      enum{MAX = 4};
    } werte;
    
    //iteration
    for(float* w = reinterpret_cast<float*>(&werte), int i=0; i < SWerte::MAX; i++)
      cout << w[i];
    //Zugriff mit namen
    cout << "papi hat  " << werte.papisgeld;
    

    Und jetz haut mich fuer den fiesen cast, ich weiss dass er unschoen ist 😉



  • 😮

    Da ist meine Variante aber schöner 😋


  • Mod

    pumuckl schrieb:

    Variante b (fuer ganz ganz seltene iterationen, naemlich unschoen!)

    struct SWerte {
      float papisgeld;
      float mamisgeld;
      float omisgeld;
      enum{MAX = 4};
    } werte;
    
    //iteration
    for(float* w = reinterpret_cast<float*>(&werte), int i=0; i < SWerte::MAX; i++)
      cout << w[i];
    //Zugriff mit namen
    cout << "papi hat  " << werte.papisgeld;
    

    Und jetz haut mich fuer den fiesen cast, ich weiss dass er unschoen ist 😉

    Das ist gar nicht so falsch mit dem cast, bedient sich aber implementationspezifischen Verhaltens. Es macht also Sinn, dieses Verhalten schon beim Compilieren testen zu können:

    static_assert<offestof(SWerte,omisgeld)==(SWerte::MAX-1)*sizeof(float)>;
    

    Diese Identität ist ausreichend.



  • Sieht aber gnadenlos ungeil aus und ist nur von Profis in seiner Funktion zu entschlüsseln.


Anmelden zum Antworten