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

Inheritance-type enum

73 views
Skip to first unread message

JiiPee

unread,
Mar 15, 2016, 8:28:35 PM3/15/16
to
Is it possible to get a behaviour of "inherited" enum? What I want is,
that I have a class, something like:

enum animal_type ....

class Dog
{
public:
animal_type GetType() { return animal_type::Dog; }
};

class Cat
{
public:
animal_type GetType() { return animal_type::Dog; }
};

and later on if I create an elephant:

class Elephant
{
public:
animal_type GetType() { return animal_type::Elephant; }
};

So how to dynamically add elements to an enum or simulate it somehow so
that when adding a new class I do not need to touch the original enum
definition but I can add the type inside the new class.

I want to be able to call a function:

void CheckAnimal(animal_type a)
{
if(a == animal_type::Elephant)
...
}

So all animals have the same type (like animal_type). I know I could
create integer constants for each animal type in each class, but then
they would be integer type which is "weak"... I would like to have
something similar to enum or class-type.

JiiPee

unread,
Mar 16, 2016, 9:30:12 AM3/16/16
to
Interesting idea, have to think about this

On 16/03/2016 00:42, Stefan Ram wrote:
> JiiPee <n...@notvalid.com> writes:
>> animal_type GetType() { return animal_type::Dog; }
>> animal_type GetType() { return animal_type::Elephant; }
>
> enum class animal_names
> {
> #define INCLUDE_FOR_ID_WITH_COMMA
> #include "all_animals.h"
> #undef INCLUDE_FOR_ID_WITH_COMMA
> TOP_SENTINEL }


what is TOP_SENTINEL here?



>
> Now to add another animal »cat«, you just add
> »cat.h« and run the make process. The script will
> generate the new »all_animals.h«.
>

Alf P. Steinbach

unread,
Mar 16, 2016, 3:48:09 PM3/16/16
to
On 16.03.2016 01:27, JiiPee wrote:
> Is it possible to get a behaviour of "inherited" enum?

Not quite, because with a values type the Is-A relationship goes the
other way than with class inheritance, which is what you have in C++.

For example, a rational number is the result of dividing one integer by
another with ordinary division, like 3/4. The set of rationals includes
the set of integers, like the set of animals includes the set of dogs,
so an integer Is-A rational, like a dog Is-An animal. But it makes sense
in C++ to have an Animal base class and a Dog derived class, because the
Dog class /adds/ information and behavior, while it does not make sense
in C++ to have a Rational base class and an Integer derived class,
because the Rational class has more information (you need two integers
to describe a rational, in general): it's ungood base.

Generally the kind of relationship involved for Rational and Integer is
modeled (or implemented) by value conversion, while the kind of
relationship for Animal and Dog is modeled by reference conversion.

But a typed enumeration is not a class, so the value conversion
technique isn't applicable.

This leaves us with no proper tools to apply, and so it's all about
choosing some suitable compromise – slightly deficient one way or another...


> What I want is, that I have a class, something like:
>
> enum animal_type ....
>
> class Dog
> {
> public:
> animal_type GetType() { return animal_type::Dog; }
> };
>
> class Cat
> {
> public:
> animal_type GetType() { return animal_type::Dog; }
> };
>
> and later on if I create an elephant:
>
> class Elephant
> {
> public:
> animal_type GetType() { return animal_type::Elephant; }
> };
>
> So how to dynamically add elements to an enum or simulate it somehow so
> that when adding a new class I do not need to touch the original enum
> definition but I can add the type inside the new class.

Instead of these integer identifiers you can probably use typeid.


> I want to be able to call a function:
>
> void CheckAnimal(animal_type a)
> {
> if(a == animal_type::Elephant)
> ...
> }
>
> So all animals have the same type (like animal_type). I know I could
> create integer constants for each animal type in each class, but then
> they would be integer type which is "weak"... I would like to have
> something similar to enum or class-type.

The only practical way I can see is declare the enum type centrally,
with values for all possible types.


Cheers!,

- Alf

Christopher Pisz

unread,
Mar 16, 2016, 6:58:59 PM3/16/16
to
On 3/15/2016 7:42 PM, Stefan Ram wrote:
> JiiPee <n...@notvalid.com> writes:
>> animal_type GetType() { return animal_type::Dog; }
>> animal_type GetType() { return animal_type::Elephant; }
>
> You would have a file
>
> dog.h
>
> /* grep_tag::is_animal */
>
> #ifdef INCLUDE_FOR_ID_WITH_COMMA
> Dog,
> #endif
>
> ...
>
> You would have a file
>
> elephant.h
>
> /* grep_tag::is_animal */
>
> #ifdef INCLUDE_FOR_ID_WITH_COMMA
> Elephant,
> #endif
>
> Then a script would use grep to generate
>
> all_animals.h
>
> #include "dog.h"
> #include "elephant.h"
>
> . It includes all files that contain »grep_tag::is_animal«.
>
> The enum would look like this:
>
> enum class animal_names
> {
> #define INCLUDE_FOR_ID_WITH_COMMA
> #include "all_animals.h"
> #undef INCLUDE_FOR_ID_WITH_COMMA
> TOP_SENTINEL }
>
> Now to add another animal »cat«, you just add
> »cat.h« and run the make process. The script will
> generate the new »all_animals.h«.
>

I didn't realize grep was part of C++
Yuck!


--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---

JiiPee

unread,
Mar 17, 2016, 10:10:31 AM3/17/16
to
On 16/03/2016 19:47, Alf P. Steinbach wrote:
>
>> So how to dynamically add elements to an enum or simulate it somehow so
>> that when adding a new class I do not need to touch the original enum
>> definition but I can add the type inside the new class.
>
> Instead of these integer identifiers you can probably use typeid.

but typeid returns a type:

std::type_info <http://en.cppreference.com/w/cpp/types/type_info>Which
would not be user defined type, its a C++ type. later on I want to have
a unique type for this: void GetAnimal(animal_type type) { ... } if I use:
void GetAnimal(std::type_info
<http://en.cppreference.com/w/cpp/types/type_info>type) { ... } then it
accepts many other types as well , other than animals type (it accepts
any type_info).


>
>
>> I want to be able to call a function:
>>
>> void CheckAnimal(animal_type a)
>> {
>> if(a == animal_type::Elephant)
>> ...
>> }
>>
>> So all animals have the same type (like animal_type). I know I could
>> create integer constants for each animal type in each class, but then
>> they would be integer type which is "weak"... I would like to have
>> something similar to enum or class-type.
>
> The only practical way I can see is declare the enum type centrally,
> with values for all possible types.

the problem i see here is that if this enum is part of the library, then
we would need to recombile the library to be able to add a new animal
type to this enum. We would need to modify the library to add a user
defined animal. Lets say the libary contains animals (types): lion, cat,
dog. then the use can add more animals , like a mouse. But if I add it
to librarys enum, then the whole libarary must be recombiled.

Öö Tiib

unread,
Mar 19, 2016, 6:40:34 AM3/19/16
to
On Thursday, 17 March 2016 16:10:31 UTC+2, JiiPee wrote:
> On 16/03/2016 19:47, Alf P. Steinbach wrote:
> >
> >> So how to dynamically add elements to an enum or simulate it somehow so
> >> that when adding a new class I do not need to touch the original enum
> >> definition but I can add the type inside the new class.
> >
> > Instead of these integer identifiers you can probably use typeid.
>
> but typeid returns a type:
>
> std::type_info <http://en.cppreference.com/w/cpp/types/type_info>Which
> would not be user defined type, its a C++ type. later on I want to have
> a unique type for this: void GetAnimal(animal_type type) { ... } if I use:
> void GetAnimal(std::type_info
> <http://en.cppreference.com/w/cpp/types/type_info>type) { ... } then it
> accepts many other types as well , other than animals type (it accepts
> any type_info).

Perhaps I do not understand what you mean. The 'typeid' returns an
object of type 'std::type_info' not type. Further, in well-defined
program an 'enum' object can have any state representable in underlying
to 'enum' type. That is because lot of existing code uses enums (instead
of better candidate 'std::bitset') to represent sets of flags.
So both with 'enum' and with 'type_info' you can have many wrong values
passed to your 'GetAnimal'.

Possibly the only benefit of 'enum' is that we can have integer value
that is same between program runs. Same can be achieved with lot less
tricks needed for example by using index value returned by
'boost::variant<all, animal, types, here>::which()' method.


JiiPee

unread,
Mar 19, 2016, 7:07:07 AM3/19/16
to
On 19/03/2016 10:40, Öö Tiib wrote:
> On Thursday, 17 March 2016 16:10:31 UTC+2, JiiPee wrote:
>> On 16/03/2016 19:47, Alf P. Steinbach wrote:
>>>> So how to dynamically add elements to an enum or simulate it somehow so
>>>> that when adding a new class I do not need to touch the original enum
>>>> definition but I can add the type inside the new class.
>>> Instead of these integer identifiers you can probably use typeid.
>> but typeid returns a type:
>>
>> std::type_info <http://en.cppreference.com/w/cpp/types/type_info>Which
>> would not be user defined type, its a C++ type. later on I want to have
>> a unique type for this: void GetAnimal(animal_type type) { ... } if I use:
>> void GetAnimal(std::type_info
>> <http://en.cppreference.com/w/cpp/types/type_info>type) { ... } then it
>> accepts many other types as well , other than animals type (it accepts
>> any type_info).
> Perhaps I do not understand what you mean. The 'typeid' returns an
> object of type 'std::type_info' not type.

yes, but I would like a type "animal_type", not std::type_info . why?
becouse std::type_info can be filled with , for example, car information
... or information about about suitcases, etc. But animal_type accepts
only animals....

Its the same with "int"- type. int can contain any integer
information... not only the size of the animal.

So I would like to limit the type to only have animal-type of
information so that the compiler would give an error if you try to pass
any other type of information

> F

Öö Tiib

unread,
Mar 19, 2016, 5:30:07 PM3/19/16
to
On Saturday, 19 March 2016 13:07:07 UTC+2, JiiPee wrote:
> On 19/03/2016 10:40, Öö Tiib wrote:
> > On Thursday, 17 March 2016 16:10:31 UTC+2, JiiPee wrote:
> >> On 16/03/2016 19:47, Alf P. Steinbach wrote:
> >>>> So how to dynamically add elements to an enum or simulate it somehow so
> >>>> that when adding a new class I do not need to touch the original enum
> >>>> definition but I can add the type inside the new class.
> >>> Instead of these integer identifiers you can probably use typeid.
> >> but typeid returns a type:
> >>
> >> std::type_info <http://en.cppreference.com/w/cpp/types/type_info>Which
> >> would not be user defined type, its a C++ type. later on I want to have
> >> a unique type for this: void GetAnimal(animal_type type) { ... } if I use:
> >> void GetAnimal(std::type_info
> >> <http://en.cppreference.com/w/cpp/types/type_info>type) { ... } then it
> >> accepts many other types as well , other than animals type (it accepts
> >> any type_info).
> > Perhaps I do not understand what you mean. The 'typeid' returns an
> > object of type 'std::type_info' not type.
>
> yes, but I would like a type "animal_type", not std::type_info . why?
> becouse std::type_info can be filled with , for example, car information
> ... or information about about suitcases, etc. But animal_type accepts
> only animals....

Oh then it seems I understood you correctly. If you want compile-time
diagnostics then neither 'enum animal_type' nor 'std::type_info' can help
you so you are in deep confusion.

JiiPee

unread,
Mar 19, 2016, 8:48:39 PM3/19/16
to
Tiib... but please... :). You know, as an experienced programmer, well
that enum *does not* accecpt for example an integer! so why you say that?

for example:

void foo(Animal animal)
{
if (animal == Animal::Elephant)
cout << "was elephant";
}

will give an compile timer error if you call it with:

foo(3);

! dont you agree?


Öö Tiib

unread,
Mar 20, 2016, 5:09:48 AM3/20/16
to
Yes I do. But the 'foo((Animal)3)' call feels as pointless as 'foo(Animal::Ape)'. Typical use case of such id value is when it
is dynamically taken from elsewhere, for example read as byte (or bytes)
from somewhere:

char value;
some_file.read(&value, 1);
Animal creature = (Animal)value;

foo(creature);

As result there won't be any compile-time checks made.

Jens Kallup

unread,
Mar 20, 2016, 6:14:40 AM3/20/16
to
What is the heck?
Try this:

#include <iostream.h>

typedef enum {
idOfAnimalUnknown = 0,
idOfAnimalCat = 1,
idOfAnimalDog = 2,
idOfAnimalElephant = 3
} Animal;

class MyAnimals
{
public:
MyAnimals(Animal what) { _animal = what; }
protected:
Animal _animal;
};

int main(void)
{
MyAnimals animal1(idOfAnimalDog);
MyAnimals * animal2 = new MyAnimals(idOfAnimalCat);

if (animal1._animal == idOfAnimalDog)
std::cout << "animal is a dog" << std::endl;

switch (animal2->_animal)
{
case idAnimalCat:
{
std::cout << "it's a cat" << std::endl;
}
break;

default:
std::cout << "unknown" << std::endl;
break;
}
delete animal2;
return 0;
}

cheers
Jens

Zaphod Beeblebrox

unread,
Mar 21, 2016, 2:06:46 PM3/21/16
to
On Wednesday, 16 March 2016 19:48:09 UTC, Alf P. Steinbach wrote:

[...]
> it does not make sense
> in C++ to have a Rational base class and an Integer derived class,

So how come it is perfectly sensible for you to have an Ellipse (2 axes) as a base class, and a Circle (just its radius) as a derived class? Isn't the set of circles contained in the set of ellipses? Having an Integer derived from a Rational is perfectly sensible, as integers *ARE* rationals: 1/1, 2/1, 3/1, 4/1, 5/1, ... and subclassing means creating an "is-a" relationship.

Note that I do not necessarily agree that classes should be designed that way, as I said. Things in OO may be different than set theory. It's not that easy: should in OO a circle be derived from an ellipse, or vice versa? Should an integer be derived from a rational or vice versa? At least, though, the principle should be consistent.



Wouter van Ooijen

unread,
Mar 21, 2016, 2:15:05 PM3/21/16
to
Op 21-Mar-16 om 7:06 PM schreef Zaphod Beeblebrox:
It is not the attributes but the contracts that determines the
inheritance hierargy.

If a rational can (according to its contract) store the value 1/2, then
you can't derive integer from rational.

If integer values are guranteed to be a whole number, then you can't
derive rational from integer.

Note that things get different for non-mutable classes.

Wouter

0 new messages