Why are enum values accessible outside the block in which enum is defined in C, but not in C++?
Consider the following C program.
#include <stdio.h> struct mystruct { enum {INT, FLOAT, STRING} type; int integer; float floating_point; } tu; /* Why is INT accessible here? */ int main() { tu.type = INT; tu.integer = 100; return 0; }
It compiles and runs fine in C.
But in C++ it fails in compilation.
#include <iostream> struct mystruct { enum {INT, FLOAT, STRING} type; int integer; float floating_point; } tu; /* Why is INT accessible here? */ int main() { tu.type = INT; tu.integer = 100; return 0; }
[Error] 'INT' was not declared in this scope
Are enum and scope rules different in C and C++?
In C, there is simply no rule for scope for enums and struct. The place where you define your enum doesn't have any importance. In C++, define something inside another something (like an enum in a class) make this something belong to the another something.
In an unscoped enum, the scope is the surrounding scope; in a scoped enum, the scope is the enum-list itself. In a scoped enum, the list may be empty, which in effect defines a new integral type. By using this keyword in the declaration, you specify the enum is scoped, and an identifier must be provided.
The benefits of using enumerations include: Reduces errors caused by transposing or mistyping numbers. Makes it easy to change values in the future. Makes code easier to read, which means it is less likely that errors will creep into it.
Enumeration or Enum in C is a special kind of data type defined by the user. It consists of constant integrals or integers that are given names by a user. The use of enum in C to name the integer values makes the entire program easy to learn, understand, and maintain by the same or even different programmer.
In C, there is simply no rule for scope for enums and struct. The place where you define your enum doesn't have any importance.
In C++, define something inside another something (like an enum in a class) make this something belong to the another something.
If you want to make your enum global in C++, you will have to define it outside your class, or access from your struct path:
#include <iostream> struct mystruct { enum {INT, FLOAT, STRING} type; int integer; float floating_point; } tu; int main() { tu.type = mystruct::INT; // INT is not in global scope, I have to precise it. tu.integer = 100; return 0; }
Note: This works in this exemple, because you are using a struct
, where everything is public
by default. Be careful; you can access your enum type and values from outside your struct or your class only if the enum is in a public
scope, as any field or function.
The main difference is that opposite to C, C++ has a class scope.
In C (6.2.1 Scopes of identifiers)
4 Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit.
Thus in this program
#include <stdio.h> struct mystruct { enum {INT, FLOAT, STRING} type; int integer; float floating_point; } tu; /* Why is INT accessible here? */ int main() { tu.type = INT; tu.integer = 100; return 0; }
Enumerators INT, FLOAT, STRING are declared outside any block scope and therefore have the file scope.
In C++ there is defined a separate scope - class scope:
3.3.7 Class scope
1 The following rules describe the scope of names declared in classes. 1) The potential scope of a name declared in a class consists not only of the declarative region following the name’s point of declaration, but also of all function bodies, default arguments, exception-specifications, and brace-or-equal-initializers of non-static data members in that class (including such things in nested classes).
and
2 The name of a class member shall only be used as follows:
— in the scope of its class (as described above) or a class derived (Clause 10) from its class,
— after the . operator applied to an expression of the type of its class (5.2.5) or a class derived from its class,
— after the -> operator applied to a pointer to an object of its class (5.2.5) or a class derived from its class,
— after the :: scope resolution operator (5.1) applied to the name of its class or a class derived from its class.
Take into account that (9.2 Class members)
1 ...Members of a class are data members, member functions (9.3), nested types, and enumerators.
Thus in this program
#include <iostream> struct mystruct { enum {INT, FLOAT, STRING} type; int integer; float floating_point; } tu; /* Why is INT accessible here? */ int main() { tu.type = INT; // Invalid access of class member tu.integer = 100; return 0; }
You shall access class member INT
in one of the following ways.
tu.type = mystruct::INT;
or
tu.type = tu.INT;
or even like
tu.type = ( &tu )->INT;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With