Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Still no inheritiance for enums?

59 views
Skip to first unread message

Christopher Pisz

unread,
Mar 20, 2017, 4:13:21 PM3/20/17
to
Is there still no mechanism to handle enums in derived classes even in C++11, 14, and 17?

For example

class Base
{
enum Color {RED, BLUE, GREEN};
};

class Derived : public Base
{
enum Color {Yellow};
};

where we want derived to have Colors: RED, BLUE, GREEN, and YELLOW


Is the way to do this still to use static const values instead?

Richard

unread,
Mar 20, 2017, 4:35:23 PM3/20/17
to
[Please do not mail me a copy of your followup]

Christopher Pisz <christo...@gmail.com> spake the secret code
<2e4fd65f-0122-496b...@googlegroups.com> thusly:

>Is there still no mechanism to handle enums in derived classes even in
>C++11, 14, and 17?
>
>For example
>
>class Base
>{
> enum Color {RED, BLUE, GREEN};
>};
>
>class Derived : public Base
>{
> enum Color {Yellow};
>};
>
>where we want derived to have Colors: RED, BLUE, GREEN, and YELLOW

Inheritance in C++ serves two purposes IMO. There is "implementation
inheritance" where you reuse code by glomming onto a bunch of stuff
from our base class and there is "interface inheritance" where we
use polymorphism to reuse code by expressing a class as a
specialization of a base class while preserving the interface.

It seems you want "implementation inheritance" for enums, but I don't
see how that is particularly useful.

When a function accepts an argument of type Base, what is it supposed
to do when I hand it an argument of type Derived and the value isn't
defined by Base?
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Christopher Pisz

unread,
Mar 20, 2017, 4:47:10 PM3/20/17
to
On Monday, March 20, 2017 at 3:35:23 PM UTC-5, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Christopher Pisz <som...@somewhere.com> spake the secret code
> <2e4fd65f-0122-496b...@googlegroups.com> thusly:
>
> >Is there still no mechanism to handle enums in derived classes even in
> >C++11, 14, and 17?
> >
> >For example
> >
> >class Base
> >{
> > enum Color {RED, BLUE, GREEN};
> >};
> >
> >class Derived : public Base
> >{
> > enum Color {Yellow};
> >};
> >
> >where we want derived to have Colors: RED, BLUE, GREEN, and YELLOW
>
> Inheritance in C++ serves two purposes IMO. There is "implementation
> inheritance" where you reuse code by glomming onto a bunch of stuff
> from our base class and there is "interface inheritance" where we
> use polymorphism to reuse code by expressing a class as a
> specialization of a base class while preserving the interface.
>
> It seems you want "implementation inheritance" for enums, but I don't
> see how that is particularly useful.
>
> When a function accepts an argument of type Base, what is it supposed
> to do when I hand it an argument of type Derived and the value isn't
> defined by Base?

Well, if we are making up how things should work, my opinion is:

Base::Foo(DERIVED::Color::YELLOW);
should throws unless Foo is virtual and it resolves to derived.
In fact, I should have to qualify Derived::YELLOW in the call, anyway.

Base::Foo(BASE::Color::RED) should work fine as is.

P.S do you see my email address every time I post to this newsgroup via crappy Google Groups? I see it when I hit reply. The thought of the incoming spam is scarey.

Jerry Stuckle

unread,
Mar 20, 2017, 6:49:33 PM3/20/17
to
On 3/20/2017 4:35 PM, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Christopher Pisz <christo...@gmail.com> spake the secret code
> <2e4fd65f-0122-496b...@googlegroups.com> thusly:
>
>> Is there still no mechanism to handle enums in derived classes even in
>> C++11, 14, and 17?
>>
>> For example
>>
>> class Base
>> {
>> enum Color {RED, BLUE, GREEN};
>> };
>>
>> class Derived : public Base
>> {
>> enum Color {Yellow};
>> };
>>
>> where we want derived to have Colors: RED, BLUE, GREEN, and YELLOW
>
> Inheritance in C++ serves two purposes IMO. There is "implementation
> inheritance" where you reuse code by glomming onto a bunch of stuff
> from our base class and there is "interface inheritance" where we
> use polymorphism to reuse code by expressing a class as a
> specialization of a base class while preserving the interface.
>
> It seems you want "implementation inheritance" for enums, but I don't
> see how that is particularly useful.
>
> When a function accepts an argument of type Base, what is it supposed
> to do when I hand it an argument of type Derived and the value isn't
> defined by Base?
>

I can see where this could be useful in some circumstances. But if the
function expects a value that's only defined in Derived it should not
accept a type Base. Just like if the function called a method that's
only defined in Derived.

However, there's another argument that Derived should be a
specialization of Base, and adding more colors violates that specialization.

I think good cases can be made both for and against it. But if it were
implemented, would it break any existing code?

--
==================
Remove the "x" from my email address
Jerry Stuckle
jstu...@attglobal.net
==================

Alf P. Steinbach

unread,
Mar 20, 2017, 7:59:19 PM3/20/17
to
On 20-Mar-17 9:13 PM, Christopher Pisz wrote:
> Is there still no mechanism to handle enums in derived classes even
> in C++11, 14, and 17?

An enum is a value type, and that means that IS-A relationship for an
extension goes the opposite way of ordinary class inheritance.

For example, if enums could be used interchangably then you would have
that enum{a, b, c} IS-A enum{a, b, c, d, e}, because any value of the
former is a valid value of the latter.

In much the same way rational numbers extends the set of values of
integers, and you just wouldn't derive class Rational from class Integer
-- an Integer always converts to an exactly corresponding Rational
and in that sense Integer IS-A Rational, but it's not the case that
every Rational IS-A Integer.

To do this properly one needs a kind of /extension/ feature, not an
inheritance feature.

I believe this was first discussed by M.I.T. professor Barbara Liskov,
in the same work where she formulated her famous substitution principle.

It should not be difficult to see why the two things relate. ;-)


> For example
>
> class Base { enum Color {RED, BLUE, GREEN}; };
>
> class Derived : public Base { enum Color {Yellow}; };
>
> where we want derived to have Colors: RED, BLUE, GREEN, and YELLOW
>
> Is the way to do this still to use static const values instead?

I'm not aware of any good solution, sorry.

The programming languages that I'm familiar with do not support notion.


Cheers!,

- Alf

Chris Vine

unread,
Mar 20, 2017, 9:20:56 PM3/20/17
to
On Mon, 20 Mar 2017 13:47:02 -0700 (PDT)
Christopher Pisz <christo...@gmail.com> wrote:
> P.S do you see my email address every time I post to this newsgroup
> via crappy Google Groups? I see it when I hit reply. The thought of
> the incoming spam is scarey.

Yes I do. But the google mail spam filters are pretty good.

Richard

unread,
Mar 21, 2017, 12:56:03 AM3/21/17
to
[Please do not mail me a copy of your followup]

I just don't see the utility in adding virtual function call overhead
to enums.

As Alf pointed out, enums are basically just fancy named integral
types. If you want polymorphism and exceptions during conversion,
then you can write your own classes to do that and have them be
constructred from fancy named integral values.

Christopher Pisz

unread,
Mar 21, 2017, 11:54:02 AM3/21/17
to
Crap. I see no option for changing that or disabling it for the first post. Only for subsequent replies.

Rick C. Hodgin

unread,
Mar 21, 2017, 12:14:46 PM3/21/17
to
On Monday, March 20, 2017 at 7:59:19 PM UTC-4, Alf P. Steinbach wrote:
> On 20-Mar-17 9:13 PM, Christopher Pisz wrote:
> > Is there still no mechanism to handle enums in derived classes even
> > in C++11, 14, and 17?
>
> An enum is a value type, and that means that IS-A relationship for an
> extension goes the opposite way of ordinary class inheritance.
>
> For example, if enums could be used interchangably then you would have
> that enum{a, b, c} IS-A enum{a, b, c, d, e}, because any value of the
> former is a valid value of the latter.

I disagree. In the construction of the class, which is derived from
a parent class at compile-time, it should augment the definition of
the input (the parent class, coupled with any other classes), such
that the final result in the child class which references the other
class(es), has a combined form which is accessible against that
object as the cumulative type. However, when referencing the same
type through one of the other objects, only those members which
were visible to them at compile-time should be referenced.

I think this is a failing in C++.

> In much the same way rational numbers extends the set of values of
> integers, and you just wouldn't derive class Rational from class Integer
> -- an Integer always converts to an exactly corresponding Rational
> and in that sense Integer IS-A Rational, but it's not the case that
> every Rational IS-A Integer.

From the point of view of each thing, they should be wholly
reconcilable, easily understood, and processed properly.

> To do this properly one needs a kind of /extension/ feature, not an
> inheritance feature.
>
> I believe this was first discussed by M.I.T. professor Barbara Liskov,
> in the same work where she formulated her famous substitution principle.
>
> It should not be difficult to see why the two things relate. ;-)

That's an incorrect application in this case. C++ has it wrong, and
the OP above has it right.

> > For example
> >
> > class Base { enum Color {RED, BLUE, GREEN}; };
> >
> > class Derived : public Base { enum Color {Yellow}; };
> >
> > where we want derived to have Colors: RED, BLUE, GREEN, and YELLOW
> >
> > Is the way to do this still to use static const values instead?
>
> I'm not aware of any good solution, sorry.
>
> The programming languages that I'm familiar with do not support notion.

That's not to say that your request doesn't make perfect sense,
Christopher Pisz ... because it does.

Base::Color would be a type with three members.
Derived::Color would be another type with four members.

It is perfectly clear in code, in meaning, in syntax (were it to
be applied that way, though I could see the need to augment the
other classes for inheritance with "enum Color {..., Yellow}" to
indicate you're adding to the prior thing).

Thank you,
Rick C. Hodgin

Tristan B. Kildaire

unread,
Mar 21, 2017, 12:47:10 PM3/21/17
to
Is enums and inheritance a useful feature? Could you explain how?

Rick C. Hodgin

unread,
Mar 21, 2017, 1:02:46 PM3/21/17
to
On Tuesday, March 21, 2017 at 12:47:10 PM UTC-4, Tristan B. Kildaire wrote:
> Is enums and inheritance a useful feature? Could you explain how?

The OP gave one.

And the usefulness is obvious: Base classes are a particular
generalized type. Inherited classes are a more specialized form
of that general type.

It would be natural to be able to extend enums to include additional
information that the base class knows nothing about in the more
specialized form.

Christopher Pisz

unread,
Mar 21, 2017, 4:11:12 PM3/21/17
to
I talked to a friend of mine during lunch, whom happens to be a .NET developer. He claims that any time he sees an enum that it raises a red flag for him. He'd rather create class for each state.

If we use an example where we make a class Socket with enum {CONNECTED, DISCONNNECTED} and then derive a class MySpecificClientSocket that wants to add a state LOGGED_IN and perhaps other derived classes that have yet more states that are only used in their specific use. He'd create a MySpecificSocketConnected, MySpecificSocketDisconnected, MySpecificSocketLoggedIn, classes that implement the specific functionality that is permitted in their states. That would make for a lot of classes! I guess that comes from a DDD mindset.

Thoughts on that?

Ian Collins

unread,
Mar 21, 2017, 4:36:20 PM3/21/17
to
On 03/22/17 09:11 AM, Christopher Pisz wrote:
>
> I talked to a friend of mine during lunch, whom happens to be a .NET
> developer. He claims that any time he sees an enum that it raises a
> red flag for him. He'd rather create class for each state.
>
> If we use an example where we make a class Socket with enum
> {CONNECTED, DISCONNNECTED} and then derive a class
> MySpecificClientSocket that wants to add a state LOGGED_IN and
> perhaps other derived classes that have yet more states that are only
> used in their specific use. He'd create a MySpecificSocketConnected,
> MySpecificSocketDisconnected, MySpecificSocketLoggedIn, classes that
> implement the specific functionality that is permitted in their
> states. That would make for a lot of classes! I guess that comes from
> a DDD mindset.
>
> Thoughts on that?

He would probably end up with the same amount of code, less the
boilerplate to define the classes. It would get quite messy with states
within states.

Having to pass classes rather than states around would necessitate they
be dynamically allocated which is probably normal on C# or Java but not
so in C++.

--
Ian

Richard

unread,
Mar 21, 2017, 4:53:52 PM3/21/17
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<ejdh5r...@mid.individual.net> thusly:

>On 03/22/17 09:11 AM, Christopher Pisz wrote:
>>
>> I talked to a friend of mine during lunch, whom happens to be a .NET
>> developer. He claims that any time he sees an enum that it raises a
>> red flag for him. He'd rather create class for each state.
>>
>> If we use an example where we make a class Socket with enum
>> {CONNECTED, DISCONNNECTED} and then derive a class
>> MySpecificClientSocket that wants to add a state LOGGED_IN and
>> perhaps other derived classes that have yet more states that are only
>> used in their specific use. He'd create a MySpecificSocketConnected,
>> MySpecificSocketDisconnected, MySpecificSocketLoggedIn, classes that
>> implement the specific functionality that is permitted in their
>> states. That would make for a lot of classes! I guess that comes from
>> a DDD mindset.
>>
>> Thoughts on that?
>
>He would probably end up with the same amount of code, less the
>boilerplate to define the classes. It would get quite messy with states
>within states.

I think his point is that enums are sometimes used to implement
"switch on enum" type behavior, which is really poor man's
polymorphism so why not just use real polymorphism directly to express
the part that invariant (base class) vs. the part that is changing
(virtual method).

There are plenty of legitimate uses of enums that don't fall into this
category.

I do see lots of poor man's polymorphism hiding in classes though. It
tends to creep up on you. First you pass in a bool to toggle
behavior, then it's a couple more bools. Then you realize that the
distinct combinations of bools are used only in individual use cases
and that they represent polymorphism, so the next time you need to add
another "sometimes do it this way" flag, you refactor to polymorphic
classes and the design becomes clearer and cleaner.

Her's an example of poor man's polymorphism:
<https://refactoring.guru/replace-conditional-with-polymorphism>

Alf P. Steinbach

unread,
Mar 21, 2017, 5:34:01 PM3/21/17
to
On 21-Mar-17 9:11 PM, Christopher Pisz wrote:
>
> I talked to a friend of mine during lunch, whom happens to be a .NET
> developer. He claims that any time he sees an enum that it raises a
> red flag for him. He'd rather create class for each state.
>
> If we use an example where we make a class Socket with enum
> {CONNECTED, DISCONNNECTED} and then derive a class
> MySpecificClientSocket that wants to add a state LOGGED_IN and
> perhaps other derived classes that have yet more states that are only
> used in their specific use. He'd create a MySpecificSocketConnected,
> MySpecificSocketDisconnected, MySpecificSocketLoggedIn, classes that
> implement the specific functionality that is permitted in their
> states. That would make for a lot of classes! I guess that comes from
> a DDD mindset.
>
> Thoughts on that?

It sounds as if you were discussing using the enum to discriminate
between different sets of functionality, different logical sub-types.

In that case (but not in the case of just using the enum to e.g. report
the current connection status) I'd agree with your friend.

Essentially, with NF different functions, each of which might or might
not apply in a given state, and each of which might be implemented
differently in some states, and with NS different states, the main
choice is between

A) NF function implementations, each of which internally discriminates
NS different states and do possibly different things in each state, or

B) MS×NF function implementations, where each set of NF implementations
is appropriate for and need consider only a given state.

The total code size can be about the same, but the latter is more
maintainable because (1) it /separates concerns/, and (2) it avoids the
/type discrimination/, which is a common anti-pattern because the
discrimination has to be updated in each of umpteen places in the code.

In order to present (B) to client code as a simple set of only NF
functions, one can use the envelope/letter idiom. As far as I know it
was first named as such by Coplien. See <url:
http://tinf2.vub.ac.be/~dvermeir/c++/EuroPLoP98.html#EnvelopeLetter>
(the images are now lacking, they may have been archived by the Wayback
Engine, possibly).

For example, the Eiffel language lacks enum support because Bertrand
Meyer wanted to discourage the common anti-pattern of discriminating on
a type indicator value (having a value that specifies how to interpret
the data) rather than using language-supported polymorphism such as the
the virtual functions of the envelope/letter-idiom.

The problem with the indicator of logical type is that, in general,
proper maintenance becomes impossible as the system grows. For when a
logical subtype is removed, or a new one is added, all places that do
such discrimination must be updated, regardless of how well hidden and
convoluted the discrimination is in each case (e.g. relying on an
assumption about how state has been set earlier in code in a completely
different source). In one very limited sense it's a case of redundancy
gone amok, having that discrimination repeated all over the place, but
it's worse because there can be e.g. logical subtype relationships that
are leveraged in different ways in different places, yielding no simple
pattern to recognize the various instances of discriminating code.

On the third hand, each case is unique, just as each human is unique,
and as each model of car is unique. “Oh it's a Ford, then it's prone to
rusting” is invalid reasoning when one knows which particular Ford model
this car is, or when one knows even more specifically that it's a 12
year old car with no rust so far. It's no good to go all overboard with
patterns and classes every which way if /a much simpler/ and smaller
solution is obtained with an enum (one case that springs to mind is a
discriminated union for a compiler's token handling). ;-)


Cheers!,

- Alf

David Brown

unread,
Mar 22, 2017, 4:24:54 AM3/22/17
to
On 21/03/17 18:02, Rick C. Hodgin wrote:
> On Tuesday, March 21, 2017 at 12:47:10 PM UTC-4, Tristan B. Kildaire wrote:
>> Is enums and inheritance a useful feature? Could you explain how?
>
> The OP gave one.
>
> And the usefulness is obvious: Base classes are a particular
> generalized type. Inherited classes are a more specialized form
> of that general type.

That bit is true...

>
> It would be natural to be able to extend enums to include additional
> information that the base class knows nothing about in the more
> specialized form.

And that bit is confused.

You first say you want to /extend/ the first enum, which is fair enough.
Then you say the extended version is more specialised, which is wrong.


It is fine for a derived class to extend a base class - but only in a
way that does not invalidate the public interface of the base class.

So you can have a base class that supports "red", "green" and "blue".
And a derived class that supports "yellow" as well. But in that case,
what happens when you have an object of the derived class that happens
to be "yellow", and you access it through the base class? It no longer
makes sense - it is invalid as an object of the base class type.

It is, of course, entirely possible to make such a system work - you
could throw an exception when the colour is used via a type that does
not understand it. You can use virtual functions. You can do some sort
of conversion to map to valid colours. You could have the derived class
keep a new member for more "advanced" colours - and so on. You could
use templates rather than classes, and make the hierarchy merely a
source code convenience without allowing run-time class hierarchy.

But however you solve the problem, you no longer have the simple and
limited public interface of "enum" (or "enum class").

See also <https://en.wikipedia.org/wiki/Liskov_substitution_principle>

Rick C. Hodgin

unread,
Mar 22, 2017, 11:53:07 AM3/22/17
to
In this case of extending enums, at no point is anything invalidated.
The definition of the child class deriving information from the parent
class introduces a new class, which is a new creation. Both are
distinct and separate, and both use their definition syntax (including
inheritance and extensions to inheritance) to produce their form.

Going backward would violate the acceptable values of the base class.
However, that is solidly the responsibility of the developer to be
aware of and address because it will require an explicit cast to be
valid to C++.

If you need a generic global enum, then make it global public. If
you're defining an enum within a class, there an explicit reason why
you're doing so. And if you're desiring to extend enums from a parent
class to greater specialization in the child class, then there's also
a reason why you're doing so.

Enums in general exist for a purpose, and their use in classes exist
for another extended purpose. The color Yellow has no validity in
the base class colors of Red, Green, Blue. It doesn't exist to that
class's knowledge so it's invalid.

If you cast a class from child (with Yellow) to parent (with only
Red, Green, Blue), then YOU are responsible for that cast. C++ does
not allow automatic type casting, but only explicit type casting,
which shift the burden of it being a compiler-requirement to ensure
the cast is an "acceptable conversion" away from the compiler, and
directly upon the shoulders of the developer (to where it should be
in my opinion).

I can think of half a dozen ways C++ could be extended to address
this issue by syntax and protocol requirements, but I think it's
such a non-issue that it's not worth implementing those features.

Cholo Lennon

unread,
Mar 22, 2017, 12:20:17 PM3/22/17
to
There is a talk (from CppCon 2016) where Ben Deane explains a similar
technique for C++ (He uses inner classes and the upcoming std::variant
to hold the current state)

CppCon 2016: Ben Deane “Using Types Effectively" (go to minute 15:10)

https://www.youtube.com/watch?v=ojZbFIQSdl8

Regards


--
Cholo Lennon
Bs.As.
ARG

Rick C. Hodgin

unread,
Mar 22, 2017, 12:33:39 PM3/22/17
to
On Wednesday, March 22, 2017 at 12:20:17 PM UTC-4, Cholo Lennon wrote:
> CppCon 2016: Ben Deane “Using Types Effectively" (go to minute 15:10)
> https://www.youtube.com/watch?v=ojZbFIQSdl8

You can automatically just to any timestamp on the desktop versions of
browsers by using the &t=XmYs syntax, such as X=minutes, Y=seconds.
For example:

CppCon 2016: Ben Deane "Using Types Effectively" (begins at 15:10)
https://www.youtube.com/watch?v=ojZbFIQSdl8&t=15m10s

Tristan B. Kildaire

unread,
Mar 22, 2017, 12:45:50 PM3/22/17
to
That is useful.

Cholo Lennon

unread,
Mar 22, 2017, 1:03:06 PM3/22/17
to
Ahhh, Ok! I didn't know that, thanks :-)
0 new messages