mirror of
https://gitlab.com/fbb-git/cppannotations
synced 2024-11-16 07:48:44 +01:00
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:
parent
5a50ecd21f
commit
692a4f49e6
7 changed files with 91 additions and 50 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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));)
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
COMMENT(>>>>>>>>>>>>> NEXT <<<<<<<<<<<<<)
|
||||
|
||||
lsect(Namespaces)(Namespaces)
|
||||
includefile(namespaces/intro)
|
||||
|
||||
|
|
Loading…
Reference in a new issue