Chapter3: The C in C++ (2)
Bitwise operators
(1)The bitwise exclusive or, or xor (^)
produces a one in the output bit if one or the other input bit is a one, but not
both.
(2)Bitwise operators can be combined with the = sign to
unite the operation and assignment: &=, |=,
and ^= are all legitimate operations (since ~
is a unary operator it cannot be combined with the =
sign).
Casting Operators
In some situations it forces the compiler to treat data as if it were (for
instance) larger than it really is, so it will occupy more space in memory; this
can trample over other data. This usually occurs when casting pointers.
(1)static_cast
static_cast用法示例:
1 //: C03:static_cast.cpp
2 void func(int) {}
3 int main() {
4 int i = 0x7fff; // Max pos value = 32767
5 long l;
6 float f;
7 // (1) Typical castless conversions:( to highlight these promotions.)
8 l = i;
9 f = i;
10 // Also works:
11 l = static_cast<long>(i);
12 f = static_cast<float>(i);
13 // (2) Narrowing conversions:( will often give you a warning)
14 i = l; // May lose digits
15 i = f; // May lose info
16 // Says "I know," eliminates warnings:
17 i = static_cast<int>(l);
18 i = static_cast<int>(f);
19 char c = static_cast<char>(i);
20 // (3) Forcing a conversion from void* :( Assigning from a void* is not allowed without a cast in C++)
21 void* vp = &i;
22 // Old way produces a dangerous conversion:
23 float* fp = (float*)vp;
24 // The new way is equally dangerous:
25 fp = static_cast<float*>(vp);
26 // (4) Implicit type conversions, normally
27 // performed by the compiler:( highlights the action)
28 double d = 0.0;
29 int x = d; // Automatic type conversion
30 x = static_cast<int>(d); // More explicit
31 func(d); // Automatic type conversion
32 func(static_cast<int>(d)); // More explicit
33 } ///:~
(2)const_cast
If you want to convert from a const to a
nonconst or from a volatile to a
nonvolatile, you use
const_cast.
(3)reinterpret_cast
This is the least safe of the casting mechanisms, and the one most likely to
produce bugs. A reinterpret_cast pretends that an object is
just a bit pattern that can be treated (for some dark purpose) as if it were an
entirely different type of object.
reinterpret_cast用法以及结果示例:
//: C03:reinterpret_cast.cpp
#include <iostream>
using namespace std;
const int sz = 100;
struct X { int a[sz]; };
void print(X* x) {
for(int i = 0; i < sz; i++)
cout << x->a[i] << ‘ ‘;
cout << endl << "--------------------" << endl;
}
int main() {
X x;
print(&x);
int* xp = reinterpret_cast<int*>(&x);
for(int* i = xp; i < xp + sz; i++)
*i = 0;
// Can‘t use xp as an X* at this point
// unless you cast it back:
print(reinterpret_cast<X*>(xp));
// In this example, you can also just use
// the original identifier:
print(&x);
} ///:~
结果如下:
(4)dynamic_cast
For type-safe downcasting. (以后介绍)
sizeof – an operator by itself
Note that sizeof is an operator, not a function. If you
apply it to a type, it must be used with the parenthesized form shown above, but
if you apply it to a variable you can use it without parentheses
Composite type creation
(1)Aliasing names with typedef
(2)Combining variables with struct
(3)Clarifying programs with enum
An enumerated data type is useful when you want to keep track of some sort of
feature:
1 //: C03:Enum.cpp
2 // Keeping track of shapes
3 enum ShapeType {
4 circle,
5 square,
6 rectangle
7 }; // Must end with a semicolon like a struct
8 int main() {
9 ShapeType shape = circle;
10 // Activities here....
11 // Now do something based on what the shape is:
12 switch(shape) {//shape is really just an int in C
13 case circle: /* circle stuff */ break;
14 case square: /* square stuff */ break;
15 case rectangle: /* rectangle stuff */ break;
16 }
17 } ///:~
18
If you don’t like the way the compiler assigns values, you can do it
yourself, like this:
1 enum
ShapeType { 2 circle =
10, square = 20,
rectangle = 50 3
};
If you give values to some names and not to others, the compiler will use the
next integral value. For example,
1 enum snap { crackle = 25,
pop };
The compiler gives pop the value 26.
If you have an instance of an enumeration color called
a. In C you can say a++, but in C++ you
can’t.
(4)Saving memory with union
>>A union piles all the data into a single space; it
figures out the amount of space necessary for the largest item you’ve put in the
union, and makes that the size of the
union.
>>All the addresses of the union variables are the
same (in a class or struct, the addresses are different).
(5)Arrays
>>Arrays cannot be passed by value.
>>Just passing the address of an array isn’t enough information; you
must always be able to know how big the array is inside your function, so you
don’t run off the end of that array.
>>argv[0] is the path and name of the program
itself.
>>All you get from the command-line is character arrays; if you want to
treat an argument as some other type, you are responsible for converting it
inside your program.
>>The bits inside of floats and
doubles are divided into three regions: the exponent, the
mantissa, and the sign bit
>>You cannot add two pointers, and if you subtract pointers the result
is the number of elements between the two pointers. However, you can add or
subtract an integral value and a pointer.
The C assert( ) macro
When you use assert( ), you give it an argument that is an
expression you are “asserting to be true.” The preprocessor generates code that
will test the assertion. If the assertion isn’t true, the program will stop
after issuing an error message telling you what the assertion was and that it
failed.
1 //: C03:Assert.cpp
2 // Use of the assert() debugging macro
3 #include <cassert> // Contains the macro
4 using namespace std;
5 int main() {
6 int i = 100;
7 assert(i != 100); // Fails
8 } ///:~
结果如下:
When you are finished debugging, you can remove the code generated by the
macro by placing the line:
#define NDEBUG
in the program before the inclusion of <cassert>, or
by defining NDEBUG on the compiler command line. NDEBUG is a flag used in
<cassert>to change the way code is generated by the
macros.
Function addresses(函数指针,考点)
(1)To define a pointer to a function that has no arguments and
no return value, you say: void (*funcPtr)(); funcPtr is a pointer to a function
that takes no arguments and returns void. But void *funcPtr()declaring a
function (that returns a void*) rather than defining a variable.
(2)void * (*(*fp1)(int))[10]: fp1 is a pointer to a function
that takes an integer argument and returns a pointer to an array of 10 void
pointers.
(3)float (*(*fp2)(int,int,float))(int): fp2 is a pointer to a
function that takes three arguments (int, int, and float) and returns a pointer
to a function that takes an integer argument and returns a float.
(4)typedef double (*(*(*fp3)())[10])();fp3 a;: An fp3 is a
pointer to a function that takes no arguments and returns a pointer to an array
of 10 pointers to functions that take no arguments and return doubles.” Then it
says “a is one of these fp3 types.”
(5)int (*(*f4())[10])(): f4 is a function that returns a pointer
to an array of 10 pointers to functions that return integers.
(6)Using a function pointer:
1 //: C03:PointerToFunction.cpp
2 // Defining and using a pointer to a function
3 #include <iostream>
4 using namespace std;
5 void func() {
6 cout << "func() called..." << endl;
7 }
8 int main() {
9 void (*fp)(); // Define a function pointer
10 fp = func; // Initialize it
11 (*fp)(); // Dereferencing calls the function
12 void (*fp2)() = func; // Define and initialize
13 (*fp2)();
14 } ///:~
(7)Arrays of pointers to functions:
This supports the concept of table-driven code; instead of using
conditionals or case statements, you select functions to execute based on a
state variable.
一个示例:
1 //: C03:FunctionTable.cpp
2 // Using an array of pointers to functions
3 #include <iostream>
4 using namespace std;
5 // A macro to define dummy functions:
6 #define DF(N) void N() { 7 cout << "function " #N " called..." << endl; }
8 DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g);
9 void (*func_table[])() = { a, b, c, d, e, f, g };
10 int main() {
11 while(1) {
12 cout << "press a key from ‘a‘ to ‘g‘ "
13 "or q to quit" << endl;
14 char c, cr;
15 cin.get(c); cin.get(cr); // second one for CR
16 if ( c == ‘q‘ )
17 break; // ... out of while(1)
18 if ( c < ‘a‘ || c > ‘g‘ )
19 continue;
20 (*func_table[c - ‘a‘])();
21 }
22 } ///:~
23
《Thinking in C++》读书笔记——Chapter 3: The C in C++ (2),码迷,mamicode.com