[class.name] [see also [dcl.typedef]]
Change: In C++, a class declaration introduces the class name into the scope where it is
declared and hides any object, function or other declaration of that name in an enclosing
scope. In C, an inner scope declaration of a struct tag name never hides the name of an
object or function in an outer scope.
Example:
int x[99];
void f() {
struct x { int a; };
sizeof(x); /* size of the array in C */
/* size of the struct in C++ */
}
Rationale:
This is one of the few incompatibilities between C and C++ that
can be attributed to the new C++ name space definition where a
name can be declared as a type and as a non-type in a single scope
causing the non-type name to hide the type name and requiring that
the keywords class, struct, union or enum be used to refer to the type name.
This new name space definition provides important notational
conveniences to C++ programmers and helps making the use of the
user-defined types as similar as possible to the use of fundamental
types.
The advantages of the new name space definition were judged to
outweigh by far the incompatibility with C described above.
Effect on original feature:
Change to semantics of well-defined feature.
Difficulty of converting:
Semantic transformation.
If the hidden name that needs to be accessed is at global scope,
the :: C++ operator can be used.
If the hidden name is at block scope, either the type or the struct
tag has to be renamed.
How widely used:
Seldom.
[class.bit]
Change:
Bit-fields of type plain int are signed.
Rationale:
Leaving the choice of signedness to implementations could lead to
inconsistent definitions of template specializations. For consistency,
the implementation freedom was eliminated for non-dependent types,
too.
Effect on original feature:
The choice is implementation-defined in C, but not so in C++.
Difficulty of converting:
Syntactic transformation.
How widely used:
Seldom.
[class.nest]
Change: In C++, the name of a nested class is local to its enclosing class. In C
the name of the nested class belongs to the same scope as the name of the outermost enclosing class.
Example:
struct X { struct Y { /* ... */ } y; }; struct Y yy; // valid C, invalid C++
Rationale:
C++ classes have member functions which require that classes
establish scopes.
The C rule would leave classes as an incomplete scope mechanism
which would prevent C++ programmers from maintaining locality
within a class.
A coherent set of scope rules for C++ based on the C rule would
be very complicated and C++ programmers would be unable to predict
reliably the meanings of nontrivial examples involving nested or
local functions.
Effect on original feature:
Change to semantics of well-defined feature.
Difficulty of converting:
Semantic transformation.
To make the struct type name visible in the scope of the enclosing
struct, the struct tag could be declared in the scope of the
enclosing struct, before the enclosing struct is defined.
Example:
struct Y; // struct Y and struct X are at the same scope struct X { struct Y { /* ... */ } y; };
All the definitions of C struct types enclosed in other struct
definitions and accessed outside the scope of the enclosing
struct could be exported to the scope of the enclosing struct.
Note: this is a consequence of the difference in scope rules,
which is documented in [basic.scope].
How widely used:
Seldom.
[class.nested.type]
Change: In C++, a typedef name may not be redeclared in a class definition after being used in that definition.
Example:
typedef int I;
struct S {
I i;
int I; // valid C, invalid C++
};
Rationale:
When classes become complicated, allowing such a redefinition
after the type has been used can create confusion for C++
programmers as to what the meaning of I really is.
Effect on original feature:
Deletion of semantically well-defined feature.
Difficulty of converting:
Semantic transformation.
Either the type or the struct member has to be renamed.
How widely used:
Seldom.