enum vs struct



  • hoi

    Simon2 schrieb:

    allerdings sehe ich eine "Unschönheit": e_tail ist jeweils ein gültiger Wert - soll er das sein ?

    das koennte zu einem prolem werden wenn ich meine fehlernummern durchgaengig haben will. die fehlercodes sind mir nummerisch jedoch egal. ansonsten muesste ich dem ersten wert schon mal einen definierten wert vorgeben. oder kann ich mich darauf verlassen, das der erste wert eines enums auf jedem compiler immer '0' bekommt?
    mir gehts dabei eigendlich nur darum das ich keine magic_numbers verweden muss.
    ansonsten wuerde ich e_tail immer am schluss anhaengen und in der ableitung oder erweiterung dann dem ersten enum-wert den e_tail der base zuweisen. dann hab ichs auch durchgehend.
    die inkonsistenz hab ich ansich garnicht, weil e_tail eh nicht dazu gehoert, zu den fehlermeldungen.

    Meep Meep



  • Meep Meep schrieb:

    re

    struct err1
    {
    	enum {e1,e2,e3,e_tail};
    };
    
    struct err2 : public err1
    {
    	enum { e_head = err1::e_tail, e4,e5,e6, e_tail};
    };
    

    Solange du so diszipliniert bist, diese Folge systematisch durchzuhalten, klappt das sicher recht gut. Aber sobald du eine weitere Klasse von err1 ableitest, hast du trotzdem wieder doppelte Fehlernummern.



  • re

    eigendlich auch ein bloedsinn das mit dem e_head. ich definiere fuer mich einfach ein keyword 'enum_end' das ich in jedem enum, das erweiterbar sein soll, am schluss angebe. und bei einer erweiterung einfach das erste element dem 'base::enum_end' zuweise.
    funktioniert ja dann aehnlich von der logik her, wie bei nem z.b. vector mit dem 'vector.end()'. das kann ich mir dann sogar noch merken ;o)

    Meep Meep



  • re

    [/quote]Solange du so diszipliniert bist, diese Folge systematisch durchzuhalten, klappt das sicher recht gut. Aber sobald du eine weitere Klasse von err1 ableitest, hast du trotzdem wieder doppelte Fehlernummern.[/quote]

    wieso denn das ? in dem fall waeren die zwei abgeleiteten klassen ja auch unterschiedlich. die zwei 'erweiterbaren enums' waeren ja nicht die selben. sie haben doch nur die gleichen elemente des urspruenglichen enums.

    Meep Meep



  • Ja, die beiden Klassen haben jeweils einen eigenen enum mit eigenen Bezeichnern, aber die Werte dahinter sind identisch:

    struct errb : public err1
    {
      enum{e_head=err1::e_tail,eb4,...}
    };
    

    ^^ jetzt werden dein err2::e4 und errb::eb4 durch den selben Wert dargestellt - das heißt, die beiden Fehlernummern wirst du später nicht mehr unterscheiden können.



  • Meep Meep schrieb:

    CStoll schrieb:

    Solange du so diszipliniert bist, diese Folge systematisch durchzuhalten, klappt das sicher recht gut. Aber sobald du eine weitere Klasse von err1 ableitest, hast du trotzdem wieder doppelte Fehlernummern.

    wieso denn das ? in dem fall waeren die zwei abgeleiteten klassen ja auch unterschiedlich. die zwei 'erweiterbaren enums' waeren ja nicht die selben. sie haben doch nur die gleichen elemente des urspruenglichen enums.

    Meep Meep

    Oh doch:

    //pseudocode
    struct Error
    {
       enum {err1, err2, err3, err_tail};
    }
    // -> Error::err1 == 0, Error::err2 == 1, Error::err3 == 2, Error::err_tail == 3
    
    struct ExtendedError1 : public Error
    {
       enum {next_err1 = Error::err_tail, next_err2, err_tail};
    }
    // -> ExtendenError1::next_err1 == 3, ExtendedError1::err2 == 4, ExtendedError1::err_tail == 5
    
    struct ExtendedError2 : public Error
    {
       enum {next_err1 = Error::err_tail, next_err2, err_tail};
    }
    // -> ExtendenError2::next_err1 == 3, ExtendedError2::err2 == 4, ExtendedError2::err_tail == 5
    

    Als 3 und 4 wurden doppelt vergeben (ExtendedError1 und ExtendedError2) - und genau das wolltest Du doch mit dem Konstrikt vermeiden, oder ?

    Gruß,

    Simon2.



  • re

    also irgendwie reden wir gerade aneinander vorbei.
    ich hab meine basis-enum:

    struct Error
    {
       enum {no_error, not_found, already_exists, enum_end};
    }
    

    jetzt moechte ich es in 2 unterschiedlichen klassen erweitern:

    struct ErrorClass1 : public Error
    {
       enum { fehler1 = Error::enum_end, fehler2, fehler3};
    }
    
    struct ErrorClass2 : public Error
    {
       enum { fehler1 = Error::enum_end, fehler2, fehler3};
    }
    

    die methode 'my_meth' der klasse 'Class1' gibt als fehlermeldung nun ErrorClass1 zurueck und die methode 'my_meth' der klasse 'Class2' gibt als fehler ErrorClass2 zurueck. unterschiedliche Errors jedoch mit bestimmten gleichen base_errors. somit kann mir dann egal sein ob in ErrorClass1 und ErrorClass2 die selben werte vorhanden sind.
    ansonsten muss ich halt ErrorClass2 von ErrorClass1 erben lassen.

    struct ErrorClass2 : public ErrorClass1
    {
       enum {next_error1 = ErrorClass1::enum_end, next_error2, next_error3, enum_end};
    }
    

    oder ich hab dich nicht richtig verstanden. dann haett ich mir jatz aber das tippen sparen koennen ;o)

    Meep Meep



  • enum's (besonders anonyme enum's wie in deinem Code) sind nichts weiter als eine nette Verpackung für int-Werte. Und wenn der Compiler zwei enum-Konstanten den selben Wert gegeben hat, kannst du sie hinterher nicht mehr auseinanderhalten.

    ansonsten muss ich halt ErrorClass2 von ErrorClass1 erben lassen.

    Ja, das solltest du - aber das wird bei größeren Projekten schnell unübersichtlich (vor allem wenn jede Teil-Bibliothek ihre eigenen Fehlernummern definieren will, mußt du ständig das halbe Projekt recompilieren, nur weil du in der obersten Error-Klasse etwas ergänzt hast).



  • Mal ne andere Frage.
    was willst du überhaupt mit errorcodes bezwecken?
    Neben den Problemen mit der eindeutigen id musst du auch darauf achten, dass der user am ende auch auf errorcodes prüft. das ist aber ein großes problem. weil viele einfach zur faulheit neigen.
    u.a. aus diesen gründen wurde ja auch exceptions eingeführt.



  • ich würde einfach das komplette enum für alle klassen in einen namespace setzen, wozu die rumeierei mit den ableitungen, wen man es auch einfach auslagern kann



  • bevor da noch jemand auf die idee kommt, das ich alle fehler in meinem programm ueber diese methode definieren will:
    ich habe insgesammt 5 klassen die von einer template-klasse ableiten.
    in der template-klasse sind 9 fehlerarten definiert. in den 5 abgeleiteten klassen kommen 3-5 neue fehlerarten dazu, welche jedoch zueinander unterschiedlich sind. damit ich nun nicht in jeder klasse die 9 gemeinsamen fehlerarten neu definieren muss, und nicht alle moeglichen fehler in die tmeplate-klasse geben muss, hab ich mich fuer diesen weg entschieden. fuer groessere sachen wuerde ich dieses konstrukt gar nicht verwenden. aber fuer diesen fall finde ich es recht gut.

    warum ich es nicht ueber exceptions mache? wie wuerde man das mit exceptions machen, damit die definitionen der fehler zentral gehalten werden koennen ?

    Meep Meep



  • zu diesem hier:

    struct err1
    {
        enum {e1,e2,e3,e_tail};
    };
    
    struct err2 : public err1
    {
        enum { e_head = err1::e_tail, e4,e5,e6, e_tail};
    };
    

    Seit wann werden den Elementen folgende Nummern zugewiesen wenn man einen Wert festgelegt hat.

    Wenn ich das richtig verstanden habe führt das dazu dass e_head = errl::e_tail ; e4 = 0; e5 = 1; usw



  • warum ich es nicht ueber exceptions mache? wie wuerde man das mit exceptions machen, damit die definitionen der fehler zentral gehalten werden koennen ?

    keine ahnung, was du mit "zentral" meinst. aber du kannst (1) viele exception-klassen schreiben, die alle verschiedene namen haben. wäre "isomorph" zu deinen ids. nur dass du die einzigartigkeit vom compiler bekommst. 2) vererbung der exceptions benutzen um die typen zu konkretisieren.

    Wenn ich das richtig verstanden habe führt das dazu dass e_head = errl::e_tail ; e4 = 0; e5 = 1; usw

    Nö, e4 = err1::e_tail+1, e5 = er1::e_tail+2, usw



  • Wieder was gelernt 🙂


Anmelden zum Antworten