Verständnisproblem mit Enum



  • Hallo

    Folgende Fehlermeldungen erscheinen:
    [C++ Fehler] E2383 Der Auswahlausdruck in den Klammern einer switch-Anweisung muß ganzzahlig sein

    Das liegt vor allem daran das du übersehen hast, das ich im Funktionskopf von Table() den Typ des Parameters "function" geändert habe. Der ist jetzt nicht mehr String, sondern FunctionType;

    void __fastcall TKepler::Table (TStringGrid *grid, String title_left, String title_right,
    int loop_index_start, int loop_index_end, /*Änderung!*/FunctionType/*Änderung*/ function, int other)
    

    Achtung : Das führt natürlich dazu das der Aufruf der Funktion ebenfalls angepasst werden muß. Siehe dazu die von mir im ersten Post erläuterte Decode-Funktion, um einem String in ein FunctionType umzuwandeln.

    Außerdem ist die doppelte Deklaration von FunctionType ungünstig. Falls du eine globale Variable namens "function" vom Typ FunctionType haben willst, dann lass das enum in der zweiten Zeile weg. Falls du gar keine globale Variable haben willst (was ich anraten würde), dann las die ganze zweite Zeile weg

    enum FunctionType {Ry, VRotation, Vlight, Vflat, mass};
    // enum FunctionType function; entweder weglassen oder ohne enum!
    

    Eine Unstimmigkeit habe ich wohl selber verursacht, indem ich den enum-Elementen den gleichen Namen wie den Funktionen gegeben habe. Am besten änderst du die enum-Deklaration und alle Verwendungen davon ab auf :

    enum FunctionType {ftRy, ftVRotation, ftVlight, ftVFlat, ftmass};
    ...
    switch (function)
    {
      case ftRy :
      {
         ...
      }
      ...
    }
    

    Achte in diesem Zusammenhang auch darauf das du die enum-Konstanten überall gleich schreibst, inklusive Groß- /Kleinschreibung.

    In deinem Codeauszug fehlt noch am Schluß eine abschließende geschweifte Klammer (kann auch durch dein Kopieren verloren gegangen sein), dann ist der Code kompilierbar.
    Ich empfehle dir aus Stil- und Übersichtsgründen noch auf die (vermutlich) globalen Variablen V, Vflat und mass1 zu verzichten und entsprechende Alternativen wie Parameter oder Membervariablen zu verwenden.

    Ich denke, dass mein Wissen noch nicht ausreicht, um die von akari angesprochende professionelle Lösung zu verwirklichen.

    Da hast du sicher recht. Für diese Lösung solltest du dich mit dynamischer Speicherverwaltung, Objektorientierung, Polymorphie sowie Design Patters auskennen, sonst hast du nichts als Ärger. Also üb dich konsequenterweise erstmal in den Grundlagen wie hier enum.

    bis bald
    akari



  • Hallo,
    vielen Dank für die schnelle Hilfe. Den geänderten Parameter habe ich wirklich übersehen! Nun ja...der Fehler ist berichigt!

    Die Funktion Table gehört zur Klasse TKepler, die ich in der Headerdatei einer anderen Unit deklariert habe. Das Problem ist nun, dass natürlich der geänderte Parameter in der Klassenvereinbarung angeglichen werden muss. Wenn ich dies aber getan habe, kommen wiederum ein Fehler:

    [C++ Fehler] Calculations.h(34): E2303 Typname erwartet

    Ich weiß leider nicht, wie ich diesen behebe. Das enum ist doch in allen Units bekannt (ich habe jede Unit in jede implentiert).

    Oder muss die Deklaration des enums an ganz andere Stelle??

    Vielen Dank für eure Hilfe
    lg, freakC++



  • Hallo

    Du must die Deklaration von FunctionType natürlich ebenfalls in den Header der Form-Unit verlegen, vor die Deklaration der Methode Table().

    bis bald
    akari



  • enums die Systemweit verwendet werden sollen, sollte man in einer eigenen Headerdatei deklarieren die man dann bei Bedarf reinziehen kann. Es macht auch Sinn diese enums in einen eigenen Namespace (oder in eine struct) zu packen um den Namensproblemen aus dem Weg zu gehen.



  • Braunstein schrieb:

    enums die Systemweit verwendet werden sollen, sollte man in einer eigenen Headerdatei deklarieren die man dann bei Bedarf reinziehen kann. Es macht auch Sinn diese enums in einen eigenen Namespace (oder in eine struct) zu packen um den Namensproblemen aus dem Weg zu gehen.

    Schon wieder zu spät... den Vorschlag wollte ich grad posten 👍



  • Hallo zusammen,
    leider habe ich mein Problem noch nicht ganz lösen können. Daher bin ich weiter auf eure Hilfe angewiesen.

    akari schrieb:
    Du must die Deklaration von FunctionType natürlich ebenfalls in den Header der Form-Unit verlegen, vor die Deklaration der Methode Table().

    Ich bin gerade leicht verwirrt 😃 . Ich habe eine Unit erstellt, in die ich folgende Zeilen hineingeschrieben habe:

    enum FunctionType {ftRy, ftVRotation, ftVlight, ftVFlat, ftmass};
    enum Function Type function;

    Diese habe ich sowohl in die Klassendeklaration als auch in die Unit mit der switch-Struktur eingebunden.

    #include "Unit1.h"  //Headerdatei mit enum ist eingebunden
    //---------------------------------------------------------------------------
    class TKepler : public TObject
    {
     public:
     ...
      void __fastcall Table (TStringGrid *grid, String title_left, String title_right,
    int loop_index_start, int loop_index_end, FunctionType function, int other); //Fehler
     ....
    

    Unit mit der switch Struktur:

    #include "Unit1.h" //Auch hier ist die Headerdatei eingebunden
    //---------------------------------------------------------------------------
    ...
    void __fastcall TKepler::Table (TStringGrid *grid, String title_left, String title_right,
    int loop_index_start, int loop_index_end, FunctionType function, int other)
    {
     for (int i=loop_index_start; i<loop_index_end; i++)
     {
      switch(function)
      {
        case ftRy :
      ...
    

    Wenn ich nun aber einfach vor die KLassendeklaration das enum schreibe, dann funktioniert es (die Headerdate mit der Klassendeklaration ist in alle anderen Units eingebunden".

    enum FunctionType {ftRy, ftVRotation, ftVlight, ftVFlat, ftmass};
    
    class TKepler : public TObject
    {
     public:
     ...
      void __fastcall Table (TStringGrid *grid, String title_left, String title_right,
    int loop_index_start, int loop_index_end, FunctionType function, int other);
     ....
    

    Warum kann ich keine Headerdatei erstellen, in welche ich das enum reinschreibe und dann diese in alle anderen Units einbinde???

    Vielen Dank für eure stetige Hilfe und bitte habt Nachsicht mit meinen wahrscheinlich sehr blöden Fragen!! 🙂
    lg, freakC++



  • Ich bin ebenfalls leicht verwirrt. Normalerweise sollte das hier einwandfrei funktionieren (ohne Namespaces/Struktur, nur die Enum Typdefinition):

    Typdefinition

    #ifndef FunctionTypeDefH
    #define FunctionTypeDefH
    
    enum FunctionTypes
    {
       ftRy, 
       ftVRotation, 
       ftVlight, 
       ftVFlat, 
       ftmass   
    };
    #endif
    

    Jetzt musst du überall dort, wo du die Enum benutzen willst, die .h Datei per #include einbinden.



  • Hallo zusammen,
    also ich bin leider gerade irgendwie zu blöd, um diese Problem zu meistern. Ich dachte eigentlich, dass ich alle eure Tipps in die Tat umgesetzt hatte. Ich fasse nochmal zusammen.

    1.) Ich erstelle eine Headerdatei mit der Deklaration des enums:

    //---------------------------------------------------------------------------
    
    #pragma hdrstop         
    
    #include "Unit1.h" //Diese Unit trägt den simplen Namen "Unit1"
    //---------------------------------------------------------------------------
    
    #pragma package(smart_init)
    
    enum FunctionType
    {
       ftRy,
       ftVRotation,    //In dieser Unit steht nicht anderes als diese
       ftVlight,       //Deklaration des enums
       ftVFlat,
       ftmass
    };
    #endif
    

    Nun habe ich meine "Table" - Funktion, die von diesem enum Gebrauch machen soll. Sie befindet sich in einer anderen Unit, weshalb ich "Unit1" in diese einbinden muss:

    ...
    include "Unit1.h" //Einbindung der Unit, damit das enum bekannt ist
    ...
    //---------------------------------------------------------------------------
    void __fastcall TKepler::Table (TStringGrid *grid, String title_left, String title_right,
    int loop_index_start, int loop_index_end, /*Fehler*/FunctionType function/*Fehler*/, int other) //Hier kommt der Fehler "Typname erwartet"
    {
     for (int i=loop_index_start; i<loop_index_end; i++)
     {
      switch(function)
      {
        case ftRy :    //Hier soll Gebrauch vom enum gemacht werden
         {
          float ry=Ry(i);
          grid->Cells[0][i] = title_left + FloatToStr (i);
          grid->Cells[1][i] = FloatToStrF (ry, ffNumber, 8, 2);
          break;
         }
        case ftVRotation:
         {
          VRotation(i);
    ...
    

    Diese Funktion gehört einer von mir erstellten Klasse an, weshalb in der Klassendeklaration natürlich auch "Unit1" miteingebunden werden muss:

    include "Unit1.h" //Unit wird wieder eingebunde, damit das enum bekannt ist
    ...
    class TKepler : public TObject
    {
     public: 
    ...
    
      void __fastcall Table (TStringGrid *grid, String title_left, String title_right,int loop_index_start, int loop_index_end,/*Fehler*/ FunctionType function/*Fehler*/, int other); //Hier erscheint der gleiche Fehler
    //Hier erscheint der gleiche Fehler "Typname erwartet"                  
    
    ...
    

    Ich habe den Eindruck, als ob bei der Einbindung der "Unit1" etwas schief geht. Wenn ich nämlich die Zeile

    include "Unit1.h"
    

    einfach weglasse, dann kommen die gleichen Fehler (wobei sie dann für mich auch verständlich sind)

    Was mache ich immer noch falsch??? Liegt es daran, dass die Unit nicht richtig eingebunden wird?? Mache ich bei der Deklaration des enums etwas falsch??

    Bitte helft mir!!
    Vielen Dank
    lg, freakC++



  • Hallo

    Du bringst die Units und Includes in der Tat durcheinander. So ist es richtig :

    // Völlig neue, ansonsten leere Unit namens MyTypes.h
    // Bitte nicht Unit1 oder andere nichtssagende Namen!
    // Von MyTypes aus sollst du keine weiteren Units includen
    
    #ifndef MY_TYPES_H
    #define MY_TYPES_H
    
    enum FunctionType
    {
       ftRy,
       ftVRotation,    //In dieser Unit steht nicht anderes als diese
       ftVlight,       //Deklaration des enums
       ftVFlat,
       ftmass
    };
    
    #endif
    
    // Die zu der Unit MyTypes.h gehörende cpp-Datei kann leer bleiben
    ...
    
    // Verwendung der MyTypes in der Unit MyForm.h
    #include "MyTypes.h"
    ...
    void __fastcall TKepler::Table (...);
    

    Nun kannst du MyTypes auch in allen anderen Units einbinden die diese brauchen.

    bis bald
    akari



  • Hallo akari,
    vielen Dank für die rasche Antwort. Nun tritt dieser Fehler endlich nicht mehr auf. Doch weiß ich eigentlich nicht, was ich nun anders gemacht habe (außer, dass ich die Unit anders genannt habe). Kannst du es mir sagen?

    Außerdem: Warum muss ich "MyTypes.h" in die Headerdatei der Unit mit der Klassendeklaration stecken?? Wenn ich "MyTypes.h" in die .cpp Datei einbinde, dann kommt der Fehler wieder!

    Ich muss nun nicht mehr in die Unit mit der switch Methode (wo dann eigentlich erst Gebrauch vom enum gemacht wird) "MyTypes.h" einzubinden, da ich die Unit mit der Klassendeklaration (in die wiederum MyTypes eingebunden ist... :p) in diese implementiert.
    Bedeutet dies, dass eine Unit quasi über eine andere auch gültig ist? Ich hoffe, ich habe mich klar ausgedrückt!!

    Vielen Dank
    lg, freakC++



  • Hallo

    Was du falsch gemacht hast kann ich nicht genau nachvollziehen, da ich deine Units nicht auseinanderhalten kann. Ich verweise nochmal auf meinen Ratschlag, immer aussagekräftige Namen zu verwenden.

    Die Wirkungsweise von include kannst du dir als ganz einfaches Kopieren von Text vorstellen. Der Compiler übernimmt alles aus der angegeben Datei und fügt es genau an die Stelle des includes ein. Nicht mehr.

    Daraus folgt
    - Für jedes Symbol das extern deklariert wird, muß vor der ersten Verwendung ein entsprechender Include stehen. Wenn ein Symbol in einer Headerdatei verwendet wird, dann reicht es nicht aus wenn der include in der zugehörigen cpp-Datei steht.
    - Die includes wirken kaskadiert. Wenn du aus Datei A die Datei B includest, werden alle includes die in B stehen auch für A gültig.

    Wenn du dir diese beiden Grundsätze durch den Kopf gehen läßt, wirst du verstehen warum meine Variante funktioniert.

    bis bald
    akari



  • akari schrieb:

    Wenn du dir diese beiden Grundsätze durch den Kopf gehen läßt, wirst du verstehen warum meine Variante funktioniert.

    Und auch, warum include-guards so wichtig sind.


Anmelden zum Antworten