S
Steven T. Hatton
Any opinions or comments on the following? I don't say it below, but I came
out on the side of using enumerations over static constants.
/* I'm trying to figure out the pros and cons of using static const
* int class members as opposed to using enumerations to accomplish a
* similar goal. The use of static constants seems more explicit and
* obvious to me. Unless I assign values to the enumerators, the
* compiler will do it for me. This has the advantage of saving
* keystrokes and digital ink. It has the disadvantage that I have to
* calculate the actual numerical value if I want to know what it
* is. With static constants, it is right there poking you in the eye.
*
* Enumerations support a rudimentary form of type checking. It may be
* useful, but possibly also deceptive. Basically any value that fits
* in the storage location used by the compiler to hold the
* enumerators will convert to the enumeration type, even if it is not
* a value of any of the enumerators. That can be useful for bounding
* a range of values, but it may also lead to a false impression that
* you are using a 'type-safe' value.
*
* The type checking can keep me honest if I want to be. That is, if
* I use the type name as an indicator that a given parameter is
* intended to be of that enumeration type, I can use the enumerators
* by name without explicit type conversions of the form Type(val).
*
* An example of where public static integral constants are used is in
* the w3c DOM recommendations. They serve as a form of poor-man's
* type checking. Each node type is assigned an integral constant
* value with an associated name. The base type of all nodes holds the
* definitions of these constants, and each derived node is assigned
* a named constant identical to one of those named in the baseclass.
*
* A purist may argue that static_cast, or dynamic_cast should be used
* instead, but static_cast only works for types known at compile
* time, and dynamic_cast incurs overhead beyond that of using a
* statically bound integral constant. I may be incorrect regarding
* this last point, but I'm pretty sure of it.
*
*
*/
/*
http://xml.apache.org/xerces-c/ApacheDOMC++BindingL2.html
*/
/*
DOMNode.hpp:
class DOMNode
{
public:
enum NodeType {
ELEMENT_NODE = 1,
ATTRIBUTE_NODE = 2,
TEXT_NODE = 3,
CDATA_SECTION_NODE = 4,
ENTITY_REFERENCE_NODE = 5,
ENTITY_NODE = 6,
PROCESSING_INSTRUCTION_NODE = 7,
COMMENT_NODE = 8,
DOCUMENT_NODE = 9,
DOCUMENT_TYPE_NODE = 10,
DOCUMENT_FRAGMENT_NODE = 11,
NOTATION_NODE = 12,
};
*/
/*
* The following is code I created to test certan uses of const and
* enum. I'll be more than happy to see alternatives, or additional
* uses of these syntactic elements.
*/
#include <iostream>
class A {
public:
/*
* We can't use A::EA or A::x before they are declared.
* Therefore the constructor is placed after the declarations,
* which are, in the case, definitions.
*/
/*
A(const A::AE& ae=A::x )
{
if(ae > x)
{
std::cout << "ae > x \n";
}
}
*/
/* Concise, but ugly.*/
/*
static const int X=0,
Y=1,
Z=2;
*/
/* More verbose, but clearer */
static const int X=0;
static const int Y=1;
static const int Z=2;
/* More concise, but more obscure to the untrained eye.*/
enum AE {x,y,z};
/* Placed after declarations (definitions) so I can use them*/
A(const A::AE& ae=A::x )
{
if(ae > x)
{
std::cout << "ae > x \n";
}
}
void f(const AE& ae)
{
if(ae > x)
{
std::cout << "ae > x \n";
}
}
/* How to make a DOM to XML generator, or syntax checker.*/
void g(const AE& ae)
{
switch(ae)
{
case A::x: std::cout << "case A::x \n";
return;
case A::y: std::cout << "case A::y \n";
return;
case A::z: std::cout << "case A::z \n";
return;
}
}
void h(const AE& ae)
{
switch(ae)
{
case A::x: std::cout << "case A::x \n";
return;
case A::y: std::cout << "case A::y \n";
return;
case A::z: std::cout << "case A::z \n";
return;
}
}
};
void i(const A::AE& ae)
{
switch(ae)
{
case A::x: std::cout << "case A::x \n";
return;
case A::y: std::cout << "case A::y \n";
return;
case A::z: std::cout << "case A::z \n";
return;
}
}
int main()
{
A a;
a.f(A::x);
a.f(A::AE(A::Z));
a.f(A::AE(5));
}
out on the side of using enumerations over static constants.
/* I'm trying to figure out the pros and cons of using static const
* int class members as opposed to using enumerations to accomplish a
* similar goal. The use of static constants seems more explicit and
* obvious to me. Unless I assign values to the enumerators, the
* compiler will do it for me. This has the advantage of saving
* keystrokes and digital ink. It has the disadvantage that I have to
* calculate the actual numerical value if I want to know what it
* is. With static constants, it is right there poking you in the eye.
*
* Enumerations support a rudimentary form of type checking. It may be
* useful, but possibly also deceptive. Basically any value that fits
* in the storage location used by the compiler to hold the
* enumerators will convert to the enumeration type, even if it is not
* a value of any of the enumerators. That can be useful for bounding
* a range of values, but it may also lead to a false impression that
* you are using a 'type-safe' value.
*
* The type checking can keep me honest if I want to be. That is, if
* I use the type name as an indicator that a given parameter is
* intended to be of that enumeration type, I can use the enumerators
* by name without explicit type conversions of the form Type(val).
*
* An example of where public static integral constants are used is in
* the w3c DOM recommendations. They serve as a form of poor-man's
* type checking. Each node type is assigned an integral constant
* value with an associated name. The base type of all nodes holds the
* definitions of these constants, and each derived node is assigned
* a named constant identical to one of those named in the baseclass.
*
* A purist may argue that static_cast, or dynamic_cast should be used
* instead, but static_cast only works for types known at compile
* time, and dynamic_cast incurs overhead beyond that of using a
* statically bound integral constant. I may be incorrect regarding
* this last point, but I'm pretty sure of it.
*
*
*/
/*
http://xml.apache.org/xerces-c/ApacheDOMC++BindingL2.html
*/
/*
DOMNode.hpp:
class DOMNode
{
public:
enum NodeType {
ELEMENT_NODE = 1,
ATTRIBUTE_NODE = 2,
TEXT_NODE = 3,
CDATA_SECTION_NODE = 4,
ENTITY_REFERENCE_NODE = 5,
ENTITY_NODE = 6,
PROCESSING_INSTRUCTION_NODE = 7,
COMMENT_NODE = 8,
DOCUMENT_NODE = 9,
DOCUMENT_TYPE_NODE = 10,
DOCUMENT_FRAGMENT_NODE = 11,
NOTATION_NODE = 12,
};
*/
/*
* The following is code I created to test certan uses of const and
* enum. I'll be more than happy to see alternatives, or additional
* uses of these syntactic elements.
*/
#include <iostream>
class A {
public:
/*
* We can't use A::EA or A::x before they are declared.
* Therefore the constructor is placed after the declarations,
* which are, in the case, definitions.
*/
/*
A(const A::AE& ae=A::x )
{
if(ae > x)
{
std::cout << "ae > x \n";
}
}
*/
/* Concise, but ugly.*/
/*
static const int X=0,
Y=1,
Z=2;
*/
/* More verbose, but clearer */
static const int X=0;
static const int Y=1;
static const int Z=2;
/* More concise, but more obscure to the untrained eye.*/
enum AE {x,y,z};
/* Placed after declarations (definitions) so I can use them*/
A(const A::AE& ae=A::x )
{
if(ae > x)
{
std::cout << "ae > x \n";
}
}
void f(const AE& ae)
{
if(ae > x)
{
std::cout << "ae > x \n";
}
}
/* How to make a DOM to XML generator, or syntax checker.*/
void g(const AE& ae)
{
switch(ae)
{
case A::x: std::cout << "case A::x \n";
return;
case A::y: std::cout << "case A::y \n";
return;
case A::z: std::cout << "case A::z \n";
return;
}
}
void h(const AE& ae)
{
switch(ae)
{
case A::x: std::cout << "case A::x \n";
return;
case A::y: std::cout << "case A::y \n";
return;
case A::z: std::cout << "case A::z \n";
return;
}
}
};
void i(const A::AE& ae)
{
switch(ae)
{
case A::x: std::cout << "case A::x \n";
return;
case A::y: std::cout << "case A::y \n";
return;
case A::z: std::cout << "case A::z \n";
return;
}
}
int main()
{
A a;
a.f(A::x);
a.f(A::AE(A::Z));
a.f(A::AE(5));
}