deriving a class - extending enum

Discussion in 'C++' started by Christopher, Dec 5, 2007.

  1. Christopher

    Christopher Guest

    I have run into this dilemma enough to ask about it now.

    Say I have a base class:

    class BaseClass
    {
    public:
    enum BaseClassEnumType
    {
    firstEnum,
    secondEnum,
    num_enumtypes
    }
    ....
    BaseClassEnumType m_something;
    };

    Down the road I make a derived class:

    class DerivedClass : public BaseClass
    {
    ....
    };

    I also have some routine(s) somewhere:

    void Foo(BaseClass * ptr)
    {
    if( ptr->m_something == BaseClass::secondEnum)
    {
    // do something
    }
    ...
    }

    Now the situation arises, when I make my derived class, where I want
    to "extend" the enumerations in the base class. In this example, I
    want to add the value "thirdEnum". In the Real World, perhaps I need
    to add more error codes specific to derived class in an error type
    enumeration that was part of the base class, or something similar. How
    do you accomplish that whether it be through redesign or some existing
    concept I am not familiar with?

    Of course, the thought of breaking the enumeration out of BaseClass
    occured to me, but it has the same result: Every time you need a new
    value in the enumeration, you have to edit preexisting code that
    "lives" in the BaseClass, in order to accomplish something that is
    specific to the derived class. This is especially problematic to me
    when the BaseClass and the enumeration are part of a separate library.

    This must be a common problem. Any thoughts?
    Christopher, Dec 5, 2007
    #1
    1. Advertising

  2. * Christopher:
    > I have run into this dilemma enough to ask about it now.
    >
    > Say I have a base class:
    >
    > class BaseClass
    > {
    > public:
    > enum BaseClassEnumType
    > {
    > firstEnum,
    > secondEnum,
    > num_enumtypes
    > }
    > ...
    > BaseClassEnumType m_something;
    > };
    >
    > Down the road I make a derived class:
    >
    > class DerivedClass : public BaseClass
    > {
    > ...
    > };
    >
    > I also have some routine(s) somewhere:
    >
    > void Foo(BaseClass * ptr)
    > {
    > if( ptr->m_something == BaseClass::secondEnum)
    > {
    > // do something
    > }
    > ...
    > }
    >
    > Now the situation arises, when I make my derived class, where I want
    > to "extend" the enumerations in the base class. In this example, I
    > want to add the value "thirdEnum". In the Real World, perhaps I need
    > to add more error codes specific to derived class in an error type
    > enumeration that was part of the base class, or something similar. How
    > do you accomplish that whether it be through redesign or some existing
    > concept I am not familiar with?


    Represent errors as a hierarchy of class types.

    Use exceptions instead of error codes.

    Don't use enums.


    Cheers, & hth.,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Dec 5, 2007
    #2
    1. Advertising

  3. Christopher

    werasm Guest

    On Dec 5, 10:39 pm, "Alf P. Steinbach" <> wrote:


    > Don't use enums.


    Never?

    Werner
    werasm, Dec 5, 2007
    #3
  4. werasm wrote:
    > On Dec 5, 10:39 pm, "Alf P. Steinbach" <> wrote:
    >
    >
    >> Don't use enums.

    >
    > Never?


    Of course never.
    Victor Bazarov, Dec 5, 2007
    #4
  5. Christopher

    werasm Guest

    On Dec 5, 10:53 pm, "Victor Bazarov" <> wrote:
    > werasm wrote:
    > > On Dec 5, 10:39 pm, "Alf P. Steinbach" <> wrote:

    >
    > >> Don't use enums.

    >
    > > Never?

    >
    > Of course never.


    Well, care to give some reasons and alternatives?

    W
    werasm, Dec 5, 2007
    #5
  6. werasm wrote:
    > On Dec 5, 10:53 pm, "Victor Bazarov" <> wrote:
    >> werasm wrote:
    >>> On Dec 5, 10:39 pm, "Alf P. Steinbach" <> wrote:

    >>
    >>>> Don't use enums.

    >>
    >>> Never?

    >>
    >> Of course never.

    >
    > Well, care to give some reasons and alternatives?


    Read Alf's response. I totally agree with him on his suggestions.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Dec 5, 2007
    #6
  7. Christopher

    werasm Guest

    On Dec 5, 10:59 pm, "Victor Bazarov" <> wrote:
    > werasm wrote:
    > > On Dec 5, 10:53 pm, "Victor Bazarov" <> wrote:
    > >> werasm wrote:
    > >>> On Dec 5, 10:39 pm, "Alf P. Steinbach" <> wrote:

    >
    > >>>> Don't use enums.

    >
    > >>> Never?

    >
    > >> Of course never.

    >
    > > Well, care to give some reasons and alternatives?

    >
    > Read Alf's response. I totally agree with him on his suggestions.


    I've read his response, hence my question (Never, or never for
    the particular problem). The question still remains.

    Regards,

    Werner
    werasm, Dec 5, 2007
    #7
  8. werasm wrote:
    > On Dec 5, 10:39 pm, "Alf P. Steinbach" <> wrote:
    >> Don't use enums.

    >
    > Never?
    > ...


    Forget it. _DO_ use enums. The hierarchy of exception classes is a good
    idea, but _not_ as a replacement for enum constants as exception codes.
    An attempt to introduce a separate exception class for every concrete
    exception type will only lead to a disaster. In the exception hierarchy
    the classes themselves are supposed to serve for a rough division of
    various exception types into relatively large groups or..., well...
    "classes" of exceptions. The concrete exception type within the class is
    still best described with a enum constant.

    Your original idea of "extending" the enum in the derived class can be
    easily implemented as follows

    class BaseException {
    public:
    enum Type {
    firstEnum,
    secondEnum,
    next_enum_,
    };

    int m_something;
    ...
    };

    class DerivedException : public BaseException {
    typedef BaseException BASE;
    public:
    enum Type {
    oneMoreEnum = BASE::next_enum_,
    yetMoreEnum,
    stillMoreEnum,
    next_enum_
    };
    ...
    };

    class DerivedDerivedException : public DerivedException {
    typedef DerivedException BASE;
    public:
    enum Type {
    oneAdditionalEnum = BASE::next_enum_,
    anotherAdditionalEnum,
    moreAdditionalEnum,
    next_enum_
    };
    ...
    };

    // And so on...

    Note how the 'next_enum_' name is used in the above example and how
    (together with the 'BASE' typedef) it makes all derived exception
    classes to have uniform definitions.

    Of course, in this case you are not really "extending" the base enum
    type, but rather create another enum type with sequence of constants
    that continue the inherited sequence. Of course, each enum is a separate
    type, but that shouldn't worry you at all: simply disregard the enum
    types entirely and use an 'int' value to describe the concrete exception
    instead.

    --
    Best regards,
    Andrey Tarasevich
    Andrey Tarasevich, Dec 5, 2007
    #8
  9. Christopher

    Howard Guest

    "Andrey Tarasevich" <> wrote in message
    news:fj79bk$tsu$...
    > werasm wrote:
    >> On Dec 5, 10:39 pm, "Alf P. Steinbach" <> wrote:
    >>> Don't use enums.

    >>
    >> Never?
    >> ...

    >
    > Forget it. _DO_ use enums. The hierarchy of exception classes is a good
    > idea, but _not_ as a replacement for enum constants as exception codes.
    > An attempt to introduce a separate exception class for every concrete
    > exception type will only lead to a disaster. In the exception hierarchy
    > the classes themselves are supposed to serve for a rough division of
    > various exception types into relatively large groups or..., well...
    > "classes" of exceptions. The concrete exception type within the class is
    > still best described with a enum constant.
    >
    > Your original idea of "extending" the enum in the derived class can be
    > easily implemented as follows
    >
    > class BaseException {
    > public:
    > enum Type {
    > firstEnum,
    > secondEnum,
    > next_enum_,
    > };
    >
    > int m_something;
    > ...
    > };
    >
    > class DerivedException : public BaseException {
    > typedef BaseException BASE;
    > public:
    > enum Type {
    > oneMoreEnum = BASE::next_enum_,
    > yetMoreEnum,
    > stillMoreEnum,
    > next_enum_
    > };
    > ...
    > };
    >
    > class DerivedDerivedException : public DerivedException {
    > typedef DerivedException BASE;
    > public:
    > enum Type {
    > oneAdditionalEnum = BASE::next_enum_,
    > anotherAdditionalEnum,
    > moreAdditionalEnum,
    > next_enum_
    > };
    > ...
    > };
    >
    > // And so on...
    >


    There's a potential problem with that: what if at some level of the
    hierarchy, you have two or more derived classes, such as DerivedException1
    and DerivedException2, both derived from BaseException? Then you'll have
    multiple enum values with the same integer value. Of course, that may not
    be any problem at all... it depends how you use the enums, I guess.
    -Howard
    Howard, Dec 5, 2007
    #9
  10. Howard wrote:
    > ...
    > There's a potential problem with that: what if at some level of the
    > hierarchy, you have two or more derived classes, such as DerivedException1
    > and DerivedException2, both derived from BaseException? Then you'll have
    > multiple enum values with the same integer value. Of course, that may not
    > be any problem at all... it depends how you use the enums, I guess.
    > ...


    The idea is that the concrete exception is supposed to be fully
    identified by the pair "class type+enum code", not by enum code alone.
    In the scenario you describe the identical enum values would belong to
    completely different "classes" (or "scopes") of exceptions. As such,
    they are not supposed to cause any conflicts.

    --
    Best regards,
    Andrey Tarasevich
    Andrey Tarasevich, Dec 5, 2007
    #10
  11. Christopher

    anon Guest

    werasm wrote:
    > On Dec 5, 10:59 pm, "Victor Bazarov" <> wrote:
    >> werasm wrote:
    >>> On Dec 5, 10:53 pm, "Victor Bazarov" <> wrote:
    >>>> werasm wrote:
    >>>>> On Dec 5, 10:39 pm, "Alf P. Steinbach" <> wrote:
    >>>>>> Don't use enums.
    >>>>> Never?
    >>>> Of course never.
    >>> Well, care to give some reasons and alternatives?

    >> Read Alf's response. I totally agree with him on his suggestions.

    >
    > I've read his response, hence my question (Never, or never for
    > the particular problem). The question still remains.


    I think they said never use enums to check errors. Or, have I misunderstood?

    You can make a base error class, from which all other error classes
    inherits. Then it is easy to add error codes by just adding classes
    together with derived classes. When error occurs, throw an error class
    anon, Dec 6, 2007
    #11
  12. Christopher

    ManicQin Guest

    On Dec 6, 10:44 am, anon <> wrote:
    > werasm wrote:
    > > On Dec 5, 10:59 pm, "Victor Bazarov" <> wrote:
    > >> werasm wrote:
    > >>> On Dec 5, 10:53 pm, "Victor Bazarov" <> wrote:
    > >>>> werasm wrote:
    > >>>>> On Dec 5, 10:39 pm, "Alf P. Steinbach" <> wrote:
    > >>>>>> Don't use enums.
    > >>>>> Never?
    > >>>> Of course never.
    > >>> Well, care to give some reasons and alternatives?
    > >> Read Alf's response. I totally agree with him on his suggestions.

    >
    > > I've read his response, hence my question (Never, or never for
    > > the particular problem). The question still remains.

    >
    > I think they said never use enums to check errors. Or, have I misunderstood?
    >
    > You can make a base error class, from which all other error classes
    > inherits. Then it is easy to add error codes by just adding classes
    > together with derived classes. When error occurs, throw an error class


    But is'nt throwing an error class is much much heavier than returning
    an enum?
    I dont see any usability/readability benefits in throwing exceptions
    over returning error codes.
    ManicQin, Dec 6, 2007
    #12
  13. Christopher

    anon Guest

    ManicQin wrote:
    > On Dec 6, 10:44 am, anon <> wrote:
    >> werasm wrote:
    >>> On Dec 5, 10:59 pm, "Victor Bazarov" <> wrote:
    >>>> werasm wrote:
    >>>>> On Dec 5, 10:53 pm, "Victor Bazarov" <> wrote:
    >>>>>> werasm wrote:
    >>>>>>> On Dec 5, 10:39 pm, "Alf P. Steinbach" <> wrote:
    >>>>>>>> Don't use enums.
    >>>>>>> Never?
    >>>>>> Of course never.
    >>>>> Well, care to give some reasons and alternatives?
    >>>> Read Alf's response. I totally agree with him on his suggestions.
    >>> I've read his response, hence my question (Never, or never for
    >>> the particular problem). The question still remains.

    >> I think they said never use enums to check errors. Or, have I misunderstood?
    >>
    >> You can make a base error class, from which all other error classes
    >> inherits. Then it is easy to add error codes by just adding classes
    >> together with derived classes. When error occurs, throw an error class

    >
    > But is'nt throwing an error class is much much heavier than returning
    > an enum?


    Yes, but only in a case when an error happens.

    > I dont see any usability/readability benefits in throwing exceptions
    > over returning error codes.


    You do not have to check error codes whenever you call functions,
    therefore code is much cleaner
    anon, Dec 6, 2007
    #13
  14. Christopher

    James Kanze Guest

    On Dec 6, 12:55 pm, ManicQin <> wrote:
    > On Dec 6, 10:44 am, anon <> wrote:
    > > werasm wrote:
    > > > On Dec 5, 10:59 pm, "Victor Bazarov" <> wrote:
    > > >> werasm wrote:
    > > >>> On Dec 5, 10:53 pm, "Victor Bazarov" <> wrote:
    > > >>>> werasm wrote:
    > > >>>>> On Dec 5, 10:39 pm, "Alf P. Steinbach" <> wrote:
    > > >>>>>> Don't use enums.
    > > >>>>> Never?
    > > >>>> Of course never.
    > > >>> Well, care to give some reasons and alternatives?
    > > >> Read Alf's response. I totally agree with him on his suggestions.


    > > > I've read his response, hence my question (Never, or never
    > > > for the particular problem). The question still remains.


    > > I think they said never use enums to check errors. Or, have
    > > I misunderstood?


    > > You can make a base error class, from which all other error
    > > classes inherits. Then it is easy to add error codes by just
    > > adding classes together with derived classes. When error
    > > occurs, throw an error class


    > But isn't throwing an error class is much much heavier than
    > returning an enum?


    That's not really the question. Depending on the type of error,
    throwing an exception might not really be appropriate.

    None of which has anything to do with the poster's original
    question, of course.

    > I dont see any usability/readability benefits in throwing
    > exceptions over returning error codes.


    If the error can't be handled locally, an exception will
    propagate it up. If it can be handled locally, of course, an
    exception is just a means of making it more awkward for the
    user. As a general rule, a function should use a return code
    unless there is no reasonable chance of handling the error
    locally.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Dec 6, 2007
    #14
  15. Christopher

    James Kanze Guest

    On Dec 5, 10:24 pm, Christopher <> wrote:
    > I have run into this dilemma enough to ask about it now.


    > Say I have a base class:


    > class BaseClass
    > {
    > public:
    > enum BaseClassEnumType
    > {
    > firstEnum,
    > secondEnum,
    > num_enumtypes
    > }
    > ...
    > BaseClassEnumType m_something;
    > };


    > Down the road I make a derived class:


    > class DerivedClass : public BaseClass
    > {
    > ...
    > };


    > I also have some routine(s) somewhere:


    > void Foo(BaseClass * ptr)
    > {
    > if( ptr->m_something == BaseClass::secondEnum)
    > {
    > // do something
    > }
    > ...
    > }


    > Now the situation arises, when I make my derived class, where
    > I want to "extend" the enumerations in the base class.


    You can't. In this case (and in general), the compiler needs to
    know all of the enum values in order to determine the size of
    the enum. Any place which could see BaseClassEnumType, and
    declare a variable of that type, may end up with a variable too
    small to hold any additional values. This would break the C++
    object model. Seriously.

    You probably don't want to. If the value is visible
    to the outside (even indirectly, e.g. as state which affects
    which functions might be called), then you can't add to it
    without violating the LSP. If it's not, then there's no problem
    defining your own enum, and using it in the derived class.

    If you want to define a contract such that the derived class can
    add to the enum, in an organized manner, it's possible, by
    reserving some range of values for the derived class, but the
    derived class will still have to define its values in a somewhat
    special way:

    class BaseClass
    {
    public:
    enum BaseClassEnumType
    {
    first,
    second,
    derivedState = 0x80
    } ;
    } ;

    class Derived
    {
    static BaseClassEnumType const
    third
    = static_cast< BaseClassEnumType >( derivedState | 1 ) ;
    static BaseClassEnumType const
    fourth
    = static_cast< BaseClassEnumType >( derivedState | 2 ) ;
    // ...
    } ;

    > In this example, I want to add the value "thirdEnum". In the
    > Real World, perhaps I need to add more error codes specific to
    > derived class in an error type enumeration that was part of
    > the base class, or something similar. How do you accomplish
    > that whether it be through redesign or some existing concept I
    > am not familiar with?


    I've mainly encountered this when a class explicitly uses some
    other class: my RegularExpression class explicitly uses my
    CharacterClass class to handle things like "[...]".
    (Explicitly, in the sense that the documentation of
    RegularExpression refers to the documentation of CharacterClass
    for such elements.) In such cases, I've done more or less as
    above:

    // Status:
    // =======
    //
    //!@brief
    //! The various states that can result after construction.
    //!
    //! This status is an attribute of the class, which can be
    //! tested anytime after the object has been constructed, and
    //! which should be tested immediately after construction,
    //! before any attempt to use the object.
    //!
    //! The last entry is used to report errors detected in
    //! #CharacterClass, and is or'ed with the results of the
    //! constructor of this class.
    //
    -----------------------------------------------------------------------
    enum Status
    {
    //! Success, the object was correctly constructed.
    //
    -------------------------------------------------------------------
    ok = 0,

    //! Empty expression. This is the status of a
    RegularExpression
    //! constructed by the default constructor.
    //
    -------------------------------------------------------------------
    emptyExpr,

    //! The delimiter specified in the constructor was a
    //! meta-character.
    //
    -------------------------------------------------------------------
    illegalDelimiter,

    //! End of file without encountering the delimiter
    //! (delimiter specified).
    //
    -------------------------------------------------------------------
    unexpectedEOF,

    //! Closing parentheses without opening parentheses, or
    //! vice versa.
    //
    -------------------------------------------------------------------
    mismatchedParen,

    //! Additional characters at the end of the expression.
    //! (I don't think that this can actually happen.)
    //
    -------------------------------------------------------------------
    garbageAtEnd,

    //! An error in the specification of a
    //! Gabi::CharacterClass. This value is in fact a set
    //! of values; the declared value represents a high order
    //! bit, which signals an error of this type, and the
    //! exact error returned by Gabi::CharacterClass is on
    //! the low order bits.
    //
    -------------------------------------------------------------------
    illegalCharClass = 0x80
    } ;

    > Of course, the thought of breaking the enumeration out of
    > BaseClass occured to me, but it has the same result: Every
    > time you need a new value in the enumeration, you have to edit
    > preexisting code that "lives" in the BaseClass, in order to
    > accomplish something that is specific to the derived class.
    > This is especially problematic to me when the BaseClass and
    > the enumeration are part of a separate library.


    The user of base class must know what to expect. If you define
    an enum with three values in the base class, a user of the base
    class might write a switch with those three values, assured that
    he had covered all cases. Or a user of the base class may use
    the enum value to index into an array with num_enumtypes
    entries. The derived class cannot add to it without breaking
    his code (and thus violating the LSP).

    If you clearly announce up front that there are special values
    which will be defined by the derived class, of course, it is
    different. Anyone using RegularExpression::Status, above, knows
    that he will need special handling if (status & 0x80) != 0.
    (Also, the presence of a value 0x80 in the enum guarantees that
    the enum type can contain values up to 0xFF, according to the
    standard.)

    > This must be a common problem. Any thoughts?


    I suspect that it's a lot less common than you think. The whole
    point of having a base class is that the user can use it without
    knowing about the derived class. For your example with error
    codes, for example, this would only be the case if the base
    class explicitly provided for the possibility. Such cases do
    exist, e.g. my RegularExpression class, but they are very, very
    rare. Most of the time, what you'll want is sub-states: the
    derived class defines an enum with additional state information,
    and the state in the derived class would be a pair of enums.
    Users of the base class only see the base class enum; users of
    the derived class can use both, effectively seeing something
    like secondEnum.a, secondEnum.b, etc.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Dec 6, 2007
    #15
  16. On Wed, 5 Dec 2007 13:24:13 -0800 (PST), Christopher wrote:
    >Now the situation arises, when I make my derived class, where I want
    >to "extend" the enumerations in the base class. In this example, I
    >want to add the value "thirdEnum". In the Real World, perhaps I need
    >to add more error codes specific to derived class in an error type
    >enumeration that was part of the base class, or something similar. How
    >do you accomplish that whether it be through redesign or some existing
    >concept I am not familiar with?


    You could experiment with the folowing approach:
    http://www.codeproject.com/KB/cpp/InheritEnum.aspx



    --
    Roland Pibinger
    "The best software is simple, elegant, and full of drama" - Grady Booch
    Roland Pibinger, Dec 6, 2007
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Matthias Kaeppler
    Replies:
    1
    Views:
    436
    R.F. Pels
    May 22, 2005
  2. Roedy Green

    extending enum

    Roedy Green, Jul 31, 2005, in forum: Java
    Replies:
    18
    Views:
    36,878
    chrismay
    Jun 25, 2011
  3. markww
    Replies:
    1
    Views:
    296
    Ivan Vecerina
    Aug 22, 2006
  4. Brian
    Replies:
    4
    Views:
    2,632
    Brian
    Feb 27, 2010
  5. Ansel

    "enum" vs. "enum class"

    Ansel, Aug 26, 2012, in forum: C++
    Replies:
    16
    Views:
    745
    Ansel
    Aug 27, 2012
Loading...

Share This Page