首页 > 代码库 > 《Thinking in C++》读书笔记——Chapter 3: The C in C++ (2)
《Thinking in C++》读书笔记——Chapter 3: The C in C++ (2)
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 = http://www.mamicode.com/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