|
Pointers and references as modifiers
So far, you’ve seen the basic data
types char, int, float, and double, along with the
specifiers signed, unsigned, short, and long, which
can be used with the basic data types in almost any combination. Now we’ve
added pointers and references that are orthogonal to the basic data types and
specifiers, so the possible combinations have just
tripled:
//: C03:AllDefinitions.cpp
// All possible combinations of basic data types,
// specifiers, pointers and references
#include <iostream>
using namespace std;
void f1(char c, int i, float f, double d);
void f2(short int si, long int li, long double ld);
void f3(unsigned char uc, unsigned int ui,
unsigned short int usi, unsigned long int uli);
void f4(char* cp, int* ip, float* fp, double* dp);
void f5(short int* sip, long int* lip,
long double* ldp);
void f6(unsigned char* ucp, unsigned int* uip,
unsigned short int* usip,
unsigned long int* ulip);
void f7(char& cr, int& ir, float& fr, double& dr);
void f8(short int& sir, long int& lir,
long double& ldr);
void f9(unsigned char& ucr, unsigned int& uir,
unsigned short int& usir,
unsigned long int& ulir);
int main() {} ///:~
Pointers and references also work when
passing objects into and out of functions; you’ll learn about this in a
later chapter.
There’s one other type that works
with pointers: void. If you state that a pointer is
a
void*, it means that any
type of address at all can be assigned to that pointer (whereas if you have an
int*, you can assign only the address of an int variable to that
pointer). For example:
//: C03:VoidPointer.cpp
int main() {
void* vp;
char c;
int i;
float f;
double d;
// The address of ANY type can be
// assigned to a void pointer:
vp = &c;
vp = &i;
vp = &f;
vp = &d;
} ///:~
Once you assign to a void* you
lose any information about what type it is. This means that before you can use
the pointer, you must cast it to the correct type:
//: C03:CastFromVoidPointer.cpp
int main() {
int i = 99;
void* vp = &i;
// Can't dereference a void pointer:
// *vp = 3; // Compile-time error
// Must cast back to int before dereferencing:
*((int*)vp) = 3;
} ///:~
The cast (int*)vp takes the
void* and tells the compiler to treat it as an int*, and thus it
can be successfully dereferenced. You might observe that this syntax is ugly,
and it is, but it’s worse than that – the void* introduces a
hole in the language’s type system. That is, it allows, or even promotes,
the treatment of one type as another type. In the example above, I treat an
int as an int by casting vp to an int*, but
there’s nothing that says I can’t cast it to a char* or
double*, which would modify a different amount of storage that had been
allocated for the int, possibly crashing the program. In general,
void pointers should be avoided, and used only in rare special cases, the
likes of which you won’t be ready to consider until significantly later in
the book.
You cannot have a
void
reference, for reasons that will be explained in Chapter
11.
|
|