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
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;
The answers given by Vlad and Arachtor are good as far as they go, but there is a question they do not address: why C++ does it differently. If someone is familiar with Stroustrup's book, they may be able to improve this, but I suppose: