by Glen McCluskey Glen McCluskey is a consultant with 15 years of experience and has focused on programming languages since 1988. He specializes in Java and C++ performance, testing, and technical documentation areas.
In this column, we'll spend some time talking about C++ classes, structs, and unions, illustrating several points unrelated to object-oriented programming. Type Names In C, a common style of usage is to say:
struct A { after which A can be used as a type name to declare objects:
void f() In C++, classes, structs, unions, and enum names are automatically type names, so you can say:
struct A { or:
enum E {ee}; By using the typedef trick, you can follow a style of programming in C somewhat like that used in C++. But there is a quirk or two when using C++. Consider usage like:
struct A { This is illegal because the int declaration A hides the struct declaration. The struct A can still be used, however, by specifying it via an "elaborated type specifier": struct A The same applies to other type names:
class A a; Taking advantage of this feature, that is, giving a class type and a variable or function the same name, isn't very good usage. It's supported for compatibility reasons with old C code; C puts structure tags (names) into a separate namespace, but C++ does not. Terms like "struct compatibility hack" and "1.5 namespace rule" are sometimes used to describe this feature. Bit Field Types Here's a small difference between C and C++. In ANSI C, bit fields must be of type "int," "signed int," or "unsigned int." In C++, they may be of any integral type, for example: enum E {e1, e2, e3};
class A { This extension was added in order to allow bit field values to be passed to functions expecting a particular type, for example:
void f(E e)
void g() Note that even with this relaxation of C rules, bit fields can be problematic to use. There are no pointers or references to bit fields in C++, and the layout and size of fields is tricky and not necessarily portable. Anonymous Unions Here's a simple one. In C++, this usage is legal:
struct A { whereas in C, you'd have to say:
struct A { giving the union a name. With the C++ approach, you can treat the union members as though they were members of the enclosing struct. Of course, the members still belong to the union, meaning that they share memory space and only one is active at a given time. Empty Classes and Structs In C, an empty struct like: struct A {}; is invalid, whereas in C++, usage like: struct A {}; or: class B {}; is perfectly legal. This type of construct is useful when developing a skeleton or placeholder for a class. An empty class has size greater than zero. Two class objects of empty classes will have distinct addresses, as in: class A {};
void f() There are still one or two C++ compilers that generate C code as their "assembly" language. To handle an empty class, they will generate a dummy member, so, for example: class A {}; becomes:
struct A { in the C output. Name Hiding Consider this small example:
#include <stdio.h>
When compiled as C code, it will typically print a value like 20 or 40, whereas when treated as C++, the output value will likely be 2 or 4. Why is this? In C++, the introduction of the local struct declaration hides the global xxx, and the program is simply taking the size of a struct which has a single integer member in it. In C, sizeof(xxx) refers to the global array, and a tag like xxx doesn't automatically refer to a struct. If we said sizeof(struct xxx), then we would be able to refer to the local struct declaration. Next month: memory allocation.
|
|
First posted: 3rd December 1997 efc Last changed: 3rd December 1997 efc |
|