Ludzie pragną czasami się rozstawać, żeby móc tęsknić, czekać i cieszyć się z powrotem.
You can’t just say Structure1 when you’re defininge variables, you must say struct Structure1. This is where typedef becomes especially handy:
//: C03:SimpleStruct2.cpp
// Using typedef with struct
Chapter 1: Data Abstraction
136
typedef struct {
char c;
int i;
float f;
double d;
} Structure2;
int main() {
Structure2 s1, s2;
s1.c = 'a';
s1.i = 1;
s1.f = 3.14;
s1.d = 0.00093;
s2.c = 'a';
s2.i = 1;
s2.f = 3.14;
s2.d = 0.00093;
} ///:~
By using typedef in this way, you can pretend that Structure2 is a built-in type, like int or float, when you define s1 and s2 (but notice it only has data – characteristics – and does not include behavior, which is what we get with real objects in C++). You’ll notice that the struct name has been left off at the beginning, because the goal is to create the typedef. However, there are times when you might need to refer to the struct during its definition. In those cases, you can actually repeat the name of the struct as the struct name and as the typedef:
//: C03:SelfReferential.cpp
// Allowing a struct to refer to itself
typedef struct SelfReferential {
int i;
SelfReferential* sr; // Head spinning yet?
} SelfReferential;
int main() {
SelfReferential sr1, sr2;
sr1.sr = &sr2;
sr2.sr = &sr1;
sr1.i = 47;
sr2.i = 1024;
} ///:~
If you look at this for awhile, you’ll see that sr1 and sr2 point to each other, as well as each holding a piece of data.
Chapter 1: Data Abstraction
137
Actually, the struct name does not have to be the same as the typedef name, but it is usually done this way as it tends to keep things simpler.
Pointers and structs
In the above examples, all the structs are manipulated as objects. However, like any piece of storage you can take the address of a struct object (as seen in SelfReferential.cpp above). To select the elements of a particular struct object, you use a ‘. ’, as seen above. However, if you have a pointer to a struct object, you must select an element of that object using a different operator: the ‘-> ’. Here’s an example:
//: C03:SimpleStruct3.cpp
// Using pointers to structs
typedef struct Structure3 {
char c;
int i;
float f;
double d;
} Structure3;
int main() {
Structure3 s1, s2;
Structure3* sp = &s1;
sp->c = 'a';
sp->i = 1;
sp->f = 3.14;
sp->d = 0.00093;
sp = &s2; // Point to a different struct object
sp->c = 'a';
sp->i = 1;
sp->f = 3.14;
sp->d = 0.00093;
} ///:~
In main( ), the struct pointer sp is initially pointing to s1, and the members of s1 are initialized by selecting them with the ‘-> ’ (and you use this same operator in order to read those members). But then sp is pointed to s2, and those variables are initialized the same way.
So you can see that another benefit of pointers is that they can be dynamically redirected to point to different objects; this provides more flexibility in your programming, as you shall
learn.
For now, that’s all you need to know about structs, but you’ll become much more comfortable with structs (and especially their more potent successors, classes) as the book progresses.
Chapter 1: Data Abstraction
138
Clarifying programs with enum
An enumerated data type is a way of attaching names to numbers, thereby giving more
meaning to anyone reading the code. The enum keyword (from C) automatically enumerates any list of words you give it by assigning them values of 0, 1, 2, etc. You can declare enum variables (which are always ints). The declaration of an enum looks similar to a struct declaration.
An enumerated data type is very useful when you want to keep track of some sort of feature:
//: C03:Enum.cpp
// Keeping track of shapes.
enum ShapeType {
circle,
square,
rectangle
}; // Must end with a semicolon like a struct
int main() {
ShapeType shape = circle;
// Activities here....
// Now do something based on what the shape is:
switch(shape) {
case circle: /* circle stuff */ break;
case square: /* square stuff */ break;
case rectangle: /* rectangle stuff */ break;
}
} ///:~