enum value question

T

Tino

In the following code, can the indicated else statement ever be
reached? It seems to me that if either Val1 or Val2 are not passed to
the constructor, then there will be a compilation error. Am I
correct?

#include <iostream>
using std::cout;
using std::endl;

typedef enum { Val1, Val2 } Venum;

class A
{
int n;
public:
A( const Venum v )
{
if( v == Val1 )
n = 1;
else if( v == Val2 )
n = 2;
else // <---- Is this necessary
n = 0;
}

int get() const
{
return n;
}
};

int main()
{
A a1( Val1 ), a2( Val2 );
cout << "a1: " << a1.get() << ", a2: " << a2.get() << endl;
return 0;
}
 
S

Sharad Kala

Tino said:
In the following code, can the indicated else statement ever be
reached?
No
It seems to me that if either Val1 or Val2 are not passed to
the constructor, then there will be a compilation error. Am I
correct?
Yes...since there is no default constructor for class A.

Best wishes,
Sharad
 
D

Daniel T.

In the following code, can the indicated else statement ever be
reached? It seems to me that if either Val1 or Val2 are not passed to
the constructor, then there will be a compilation error. Am I
correct?

#include <iostream>
using std::cout;
using std::endl;

typedef enum { Val1, Val2 } Venum;

class A
{
int n;
public:
A( const Venum v )
{
if( v == Val1 )
n = 1;
else if( v == Val2 )
n = 2;
else // <---- Is this necessary
n = 0;
}

int get() const
{
return n;
}
};

int main()
{
A a1( Val1 ), a2( Val2 );
cout << "a1: " << a1.get() << ", a2: " << a2.get() << endl;
return 0;
}

Presumably, you have already tried to do it with your compiler yes? What
happened when you did:

int main()
{
A a1( (Venum)5 );
cout << "a1: " << a1.get() << endl;
}
 
J

Jeff Schwab

Tino said:
In the following code, can the indicated else statement ever be
reached? It seems to me that if either Val1 or Val2 are not passed to
the constructor, then there will be a compilation error. Am I
correct?

#include <iostream>
using std::cout;
using std::endl;

typedef enum { Val1, Val2 } Venum;

class A
{
int n;
public:
A( const Venum v )
{
if( v == Val1 )
n = 1;
else if( v == Val2 )
n = 2;
else // <---- Is this necessary
n = 0;
}

int get() const
{
return n;
}
};

int main()
{
A a1( Val1 ), a2( Val2 );
cout << "a1: " << a1.get() << ", a2: " << a2.get() << endl;
return 0;
}

It depends. On some implementations, Venum will be able to hold more
than one bit, and values other than Val1 and Val2 will be possible. On
other implementations, this will not be the case. In general, be
prepared for enum's to hold unintended values. For example: If you put
three identifiers in your enum's definition, instead of two, you
probably will be able to construct a Venum from the value 3, and an A
from the resulting Venum.
 
H

Howard

Sharad Kala said:
Yes...since there is no default constructor for class A.

That's not neccessarily true. I'm not sure what the standard says about it,
but in my tests I've been able to define a variable of type Venum, then
assign a value to it via a c-style cast, and then create an object of class
A passing it an invalid value. Like this:

Venum e;
e = (Venum)25;
A testA(e);

This calls that same constructor with the correct type, but at runtime the
value is 25, which is neither Val1 or Val2.

Perhaps it is implementation-dependant, but it works for me!

I always provide a default case (using switch statements) when handling
enumerations, (and may also add Assert statements) to make sure I don't have
invalid values when passing enumerated values.

-Howard
 
K

Keith H Duggar

Daniel and Jeff are both correct.

I'm not sure what your intent is with this enum so I have a few
questions.

First, since you are using enums why does A contain an int instead of
a Venum? Second, does it make sense in your context to encapsulate the
enum inside the class to prevent name pollution? If so, encapsulation
will also all you to control access to the enum to preventing casting.

In other words, how about this code ( names changed a bit ):

#include <iostream>

class Venomous {

enum Venom { HAEMO , NEURO } ;

Venom __venom ;

public :

static Venom const haemo ( ) { return HAEMO ; }
static Venom const neuro ( ) { return NEURO ; }

Venomous ( Venom venom ) : __venom ( venom ) { }

Venom venom ( ) const { return __venom ; }

void venom ( Venom venom ) { __venom = venom ; }

} ;

std::eek:stream & operator<< ( std::eek:stream & s , Venomous v ) {
return s << (
v.venom() == Venomous::haemo() ? "HAEMO\n" :
v.venom() == Venomous::neuro() ? "NEURO\n" : "UNKNOWN\n" ) ;
}

int main ( int argc , char* argv[] ) {

Venomous viper ( Venomous::haemo() ) ;
Venomous cobra ( Venomous::neuro() ) ;

// the following will not compile
Venomous basilisk ( (Venomous::Venom) 1000 ) ;

std::cout << viper << cobra << basilisk ;

}

This solution seems to solve your problem. However, clients will not
be able to allocate or manipulate objects of type Venom. If you want
to allow this in addition to restricting values you will need to
change Venom to a class with a private constructor and static
functions that provide valid values similar to the above. This is
described by Meyers in one of the "Effective" books using a Month
class to illustrate.
 
S

Sharad Kala

Howard said:
That's not neccessarily true. I'm not sure what the standard says about it,
but in my tests I've been able to define a variable of type Venum, then
assign a value to it via a c-style cast, and then create an object of class
A passing it an invalid value. Like this:

Venum e;
e = (Venum)25;
A testA(e);

This calls that same constructor with the correct type, but at runtime the
value is 25, which is neither Val1 or Val2.

Perhaps it is implementation-dependant, but it works for me!

I always provide a default case (using switch statements) when handling
enumerations, (and may also add Assert statements) to make sure I don't have
invalid values when passing enumerated values.

True, even I have observed this.
I was answering in the context that if no value is passed to the c'tor then what
would be the behavior.
Thanks for pointing that out.

-Sharad
 
N

Nick Hounsome

Why not
enum Venum {Val1,Val2}; ??

Better still why not Venom instead of Venum?

Not unless you want to try to defend against client code
deliberately being perverse.

How does this help - If you are going to try to continue I
would expect you to use one of the 'valid' values.

Why not just
enum Venum {Val1=1,Val2=2};
and forget about A?
It depends. On some implementations, Venum will be able to hold more
than one bit, and values other than Val1 and Val2 will be possible. On
other implementations, this will not be the case. In general, be
prepared for enum's to hold unintended values. For example: If you put
three identifiers in your enum's definition, instead of two, you
probably will be able to construct a Venum from the value 3, and an A
from the resulting Venum.

I may be wrong but I think the standard might actually say that it will
be the same underlying thing as int unless it needs to be long because of
one of the declared values.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,111
Latest member
VetaMcRae
Top