Completed First Imressions, Namespaces next

git-svn-id: https://cppannotations.svn.sourceforge.net/svnroot/cppannotations/trunk@258 f6dd340e-d3f9-0310-b409-bdd246841980
This commit is contained in:
Frank B. Brokken 2009-10-20 07:54:32 +00:00
parent 5a50ecd21f
commit 692a4f49e6
7 changed files with 91 additions and 50 deletions

View file

@ -49,12 +49,12 @@ COMMENT( 2 )
lchapter(IntroC)(Introduction)
includefile(intro)
COMMENT(>>>>>>>>>>>>> NEXT <<<<<<<<<<<<<)
COMMENT( 3 )
lchapter(FirstImpression)(A First Impression Of C++)
includefile(first)
COMMENT(>>>>>>>>>>>>> NEXT <<<<<<<<<<<<<)
COMMENT( 4 )
lchapter(NAMESPACE)(Name Spaces)
includefile(namespaces)

View file

@ -76,8 +76,6 @@ includefile(first/cast)
subsect(The `static_cast'-operator)
includefile(first/staticcast)
COMMENT(>>>>>>>>>>>>> NEXT <<<<<<<<<<<<<)
subsect(The `const_cast'-operator)
includefile(first/constcast)

View file

@ -1,30 +1,17 @@
it() There is a special cast to do away with the tt(const)
type-modification:
The tt(const) keyword has been given a special place in casting. Normally
anything tt(const) is tt(const) for a good reason. Nonetheless situations
may be encountered where the tt(const) can be ignored. For these special
situations the tt(const_cast) should be used. Its syntax is:
centt(const_cast<type>(expression))
it() A third cast is used to change the em(interpretation) of information:
centt(reinterpret_cast<type>(expression))
it() And, finally, there is a cast form which is used in combination with
polymorphism (see chapter ref(POLYMORPHISM)). The
centt(dynamic_cast<type>(expression))
is performed run-time to convert, e.g., a pointer to an object of a
certain class to a pointer to an object further down its so-called em(class
hierarchy). At this point in the em(Annotations) it is a bit premature to
discuss the tt(dynamic_cast), but we will return to this topic in section
ref(DYNAMICCAST).
)
A ti(const_cast<type>(expression)) expression is used to undo the
tt(const) attribute of a (pointer) type.
The ti(const_cast<type>(expression)) operator is used to undo the
tt(const)-ness of a (pointer) type. Assume that a function
tt(fun(char *s)) is available, which performs some operation on its
tt(char *s) parameter. Furthermore, assume that it's em(known) that the
function does not actually alter the string it receives as its argument. How
can we use the function with a string like tt(char const hello[] = "Hello
world")?
Passing tt(hello) to tt(fun()) produces the warning
centt(passing `const char *' as argument 1 of `fun(char *)' discards const)
which can be prevented using the call
centt(fun(const_cast<char *>(hello));)
The need for a tt(const_cast) may occur in combination with functions from
the standard bf(C) library which traditionally weren't always as const-aware
as they should. A function tt(strfun(char *s)) might be available, performing
some operation on its tt(char *s) parameter without actually modifying the
characters pointed to by tt(s). Passing tt(char const hello[] = "hello";) to
tt(strfun) will produce the warning
centt(passing `const char *' as argument 1 of `fun(char *)' discards const)
A tt(const_cast) is the appropriate way to prevent the warning:
centt(strfun(const_cast<char *>(hello));)

View file

@ -1,2 +1,8 @@
The ti(dynamic_cast<>()) operator is used in the context of
i(polymorphism). Its discussion is postponed until section ref(DYNAMICCAST).
Finally there is a new style cast that is used in combination with
polymorphism (see chapter ref(POLYMORPHISM)). Its syntax is:
centt(dynamic_cast<type>(expression))
It is used run-time to convert, a pointer to an object of a class to a
pointer to an object of a class that is found further down its so-called
em(class hierarchy) (which is also called a em(downcast)). At this point in
the em(Annotations) a tt(dynamic_cast) cannot yet be discussed extensively,
but we will return to this topic in section ref(DYNAMICCAST).

View file

@ -1,17 +1,53 @@
The ti(reinterpret_cast<type>(expression)) operator is used to reinterpret
pointers. For example using a tt(reinterpret_cast<>()) the individual
bytes making up a tt(double) value can easily be reached. Assume tt(doubleVar)
is a variable of type tt(double), then the individual bytes can be reached
using
centt(reinterpret_cast<char *>(&doubleVar))
This particular example also suggests the danger of the cast: it looks as
though a standard tt(C)-string is produced, but there is not normally a
trailing 0-byte. It's just a way to reach the individual bytes of the memory
holding a double value.
The third new-style cast is used to change the em(interpretation) of
information: the tt(reinterpret_cast). It is somewhat reminiscent of the
tt(static_cast), but tt(reinterpret_cast) should be used when it is em(known)
that the information as defined in fact is or can be interpreted as something
completely different. Its syntax is:
centt(reinterpret_cast<pointer type>(pointer expression))
More in general: using the cast-operators is a dangerous habit, as it
suppresses the normal type-checking mechanism of the compiler. It is suggested
to i(prevent casts) if at all possible. If circumstances arise in which casts
have to be used, document the reasons for their use well in your code, to make
double sure that the cast will not eventually be the underlying cause for a
program to misbehave.
A ti(reinterpret_cast<type>(expression)) operator is appropriately used to
reinterpret a tt(void *) to a pointer of a well-known type. Void pointers are
encountered with functions from the bf(C) library like tt(qsort). The
tt(qsort) function expects a pointer to a (comparison) function having two
tt(void const *) parameters. In fact, the tt(void const *)s point to data
elements of the array to sort, and so the comparison function may cast the
tt(void const *) parameters to pointers to the elements of the array to be
sorted. E.g., if the array is an tt(int array[]) and the compare function's
parameters are tt(void const *p1, void const *p2)
then the compare function may obtain the address of the tt(int) pointed to by
tt(p1) by using:
centt(reinterpret_cast<int const *>(p1))
Another example of a tt(reinterpret_cast) is found in combination with the
tt(write) functions that are available for files and streams. In bf(C++)
streams are the preferred interface to, e.g., files. Output
streams (like tt(cout)) offer tt(write) members having the prototype
centt(write(char const *buffer, int length))
To write a tt(double) to a stream using tt(write) a tt(reinterpret_cast) is
needed as well. E.g., to write the raw bytes of a variable tt(double value) to
tt(cout) we would use:
verb(
cout.write(reinterpret_cast<char const *>(&value), sizeof(double));
)
All casts are potentially dangerous, but the tt(reinterpret_cast) is the
most dangerous of all casts. Effectively we tell the compiler: back off, we
know what we're doing, so stop fuzzing. All bets are off, and we'd better
em(do) know what we're doing in situations like these. As a case in point
consider the following code:
verb(
int value = 0x12345678; // assume a 32-bits int
cout << "Value's first byte has value: " << hex <<
static_cast<int>(
*reinterpret_cast<unsigned char *>(&value)
);
)
The above code will show different results on little and big endian
computers. Little endian computers will show the value 78, big endian
computers the value 12. Also note that the different representations used by
little and big endian computers renders the previous example
(tt(cout.write(...))) non-portable over computers of different architectures.
As a i(rule of thumb): if circumstances arise in which casts em(have) to be
used, clearly document the reasons for their use in your code, making double
sure that the cast will not eventually cause a program to misbehave.

View file

@ -31,3 +31,15 @@ These two casts are a bit overdone. The same result is obtained by
explicitly casting tt(doubleVar) to an tt(int), thus obtaining an
tt(int)-value for the right-hand side of the expression:
centt(intVar += static_cast<int>(doubleVar);)
A tt(static_cast) can also be used to undo or introduce the
signed-modifier of an tt(int)-typed variable. The bf(C) function tt(tolower)
requires an tt(int) representing the value of an tt(unsigned char). But
tt(char) by default is a signed type. To call tt(tolower) using an available
tt(char ch) we should use:
centt(tolower(static_cast<unsigned char>(ch)))
Casts like these provide information to the compiler about how to handle
the provided data. Very often (especially with data types differing only in
size but not in representation) the cast won't require any additional
code. Additional code will be required, however, to convert one representation
to another, e.g., when converting tt(double) to tt(int).

View file

@ -1,3 +1,5 @@
COMMENT(>>>>>>>>>>>>> NEXT <<<<<<<<<<<<<)
lsect(Namespaces)(Namespaces)
includefile(namespaces/intro)