Chapter 2. Variables and Basic Types
ios
1:When assigning an out-of-range value to a signed type, it is up to the compiler to decide what value to assign. In practice, many compilers treat signed types similarly to how they are required to treat unsigned types. That is, they do the assignment as the remainder modulo the size of the type. However, we are not guaranteed that the compiler will do so for the signed types.
(當將超過取值範圍的值賦給 signed 類型時,由編譯器決定實際賦的值。在實際操做中,不少的編譯器處理 signed 類型的方式和 unsigned 類型相似。也就是說,賦值時是取該值對該類型取值數目求模後的值。然而咱們不能保證編譯器都會這樣處理 signed 類型。)
2:In fact, on some machines, double precision is faster than single. The precision offered by long double usually is unnecessary and often entails considerable extra run-time cost.
(有些機器上,double 類型比 float 類型的計算要快得多。long double 類型提供的精度一般沒有必要,並且還須要承擔額外的運行代價)程序員
3:The copy-initialization syntax uses the equal (=) symbol; direct-initialization places the initializer in parentheses數組
(複製初始化語法用等號(=),直接初始化則是把初始化式放在括號中): app
int ival(1024); // direct-initialization int ival = 1024; // copy-initialization
4:Each class may define one or more special member functionsthat say how we can initialize variables of the class type. The member functions that define how initialization works are known as constructors
less
(每一個類均可能會定義一個或幾個特殊的成員函數來告訴咱們如何初始化類類型的變量。定義如何進行初始化的成員函數稱爲構造函數)
curl
5: then we can define variables of that class without explicitly initializing them. For example, the string type defines its default constructor to initialize the string as an empty stringthat is, a string with no characters:
(若是類具備默認構造函數,那麼就能夠在定義該類的變量時不用顯式地初始化變量。例如,string 類定義了默認構造函數來初始化 string 變量爲空字符串,即沒有字符的字符串:)ide
std::string empty; // empty is the empty string; empty =""
6: #include <iostream>函數
int main() { int sum = 0; // sum values from 1 up to 10 inclusive for (int val = 1; val <= 10; ++val) sum += val; // equivalent to sum = sum + val std::cout << "Sum of 1 to 10 inclusive is " << sum << std::endl; return 0; }
8:A portion of a program in which names have meaning. C++ has several levels of scope:oop
程序的一部分,在其中名字有意義。C++ 含有下列幾種做用域:post
global names defined outside any other scope.
全局——名字定義在任何其餘做用域外。
class names defined by a class.
類——名字由類定義。
namespace names defined within a namespace.
命名空間——名字在命名空間中定義。
local names defined within a function.
局部——名字在函數內定義。
block names defined within a block of statements, that is, within a pair of curly braces.
塊——名字定義在語句塊中,也就是說,定義在一對花括號裏。
statement names defined within the condition of a statement, such as an if, for, or while.
語句——名字在語句( 如if、while 和 for 語句)的條件內定義。
按做用域分,全局變量在整個工程文件內都有效;靜態全局變量只在定義它的文件內有效;靜態局部變量只在定義它的函 數內有效,只是程序僅分配一次內存,函數返回後,該變量不會消失;局部變量在定義它的函數內有效,可是函數返回後失效。
1. Two of the most important library types are string and vector. The string type supports variable-length character strings. The vector type holds a sequence of objects of a specified type. These types are important because they offer improvements over more primitive types defined by the language.(兩種最重要的標準庫類型是 string 和 vector。string 類型支持長度可變的字符串,vector 可用於保存一組指定類型的對象)
2. 幾種初始化 string 對象的方式
string s1; |
Default constructor; s1 is the empty string |
|
默認構造函數 s1 爲空串 |
string s2(s1); |
Initialize s2 as a copy of s1 |
|
將 s2 初始化爲 s1 的一個副本 |
string s3("value"); |
Initialize s3 as a copy of the string literal |
|
將 s3 初始化爲一個字符串字面值副本 |
string s4(n, 'c'); |
Initialize s4 with n copies of the character 'c' |
|
將 s4 初始化爲字符 'c' 的 n 個副本 |
(因爲 getline 函數返回時丟棄換行符,換行符將不會存儲在 string 對象中)
4. string Operations
s.empty() |
Returns true if s is empty; otherwise returns false 若是 s 爲空串,則返回 true,不然返回 false。 |
s.size() |
Returns number of characters in s 返回 s 中字符的個數 |
s[n] |
Returns the character at position n in s; positions start at 0. 返回 s 中位置爲 n 的字符,位置從 0 開始計數 |
s1 + s2 |
Returns a string equal to the concatenation of s1 and s2 把 s1 和s2 鏈接成一個新字符串,返回新生成的字符串 |
s1 = s2 |
Replaces characters in s1 by a copy of s2 把 s1 內容替換爲 s2 的副本 |
v1 == v2 |
Returns true if v1 and v2 are equal; false otherwise 比較 v1 與 v2的內容,相等則返回 true,不然返回 false |
!=, <, <=, >, and >= |
Have their normal meanings 保持這些操做符慣有的含義 |
string phrase = "Hello World"; string slang = "Hiya";
then substr is less than phrase, and slang is greater than either substr or phrase.
(則 substr 小於 phrase,而 slang 則大於 substr 或 phrase )
6. When mixing strings and string literals, at least one operand to each + operator must be of string type:
當進行 string 對象和字符串字面值混合鏈接操做時,+ 操做符的左右操做數必須至少有一個是 string 類型的:
string s1 = "hello"; // no punctuation string s2 = "world"; string s3 = s1 + ", "; // ok: adding a string and a literal string s4 = "hello" + ", "; // error: no string operand string s5 = s1 + ", " + "world"; // ok: each + has string operandstring s6 = "hello" + ", " + s2; // error: can't add string literals // because: "hello" + "," error
7.To use size_type, we must name the type in which it is defined. A vector type always includes the element type of the vector:
(使用 size_type 類型時,必須指出該類型是在哪裏定義的。vector 類型老是包括老是包括 vector 的元素類型) |
vector<int>::size_type // ok vector::size_type // error
8.Programmers new to C++ sometimes think that subscripting a vector adds elements; it does not:
(初學 C++ 的程序員可能會認爲 vector 的下標操做能夠添加元素,其實否則:)
vector<int> ivec; // empty vector for (vector<int>::size_type ix = 0; ix != 10; ++ix)ivec[ix] = ix; // disaster: ivec has no elements
succeed:
for (vector<int>::size_type ix = 0; ix != 10; ++ix) ivec.push_back(ix); // ok: adds new element with value ix
9. C programmers are probably also suprised that we call the size member in the for rather than calling it once before the loop and remembering its value.(C 程序員難以理解的還有,上例中沒有在 for 循環以前就調用 size 成員函數並保存其返回的值,而是在 for 語句頭中調用 size 成員函數。)
10. What's important to understand is that there is a collection of types that serve as iterators. These types are related conceptually. We refer to a type as an iterator if it supports a certain set of actions. Those actions let us navigate among the elements of a container and let us access the value of those elements.(重點要理解的是,有許多用做迭代器的類型,這些類型在概念上是相關的。若一種類型支持一組肯定的操做(這些操做可用來遍歷容器內的元素,並訪問這些元素的值),咱們就稱這種類型爲迭代器。)
11.
const vector<int> nines(10, 9); // cannot change elements in nines // error: cit2 could change the element it refers to and nines is const const vector<int>::iterator cit2 = nines.begin(); // ok: it can't change an element value, so it can be used with a const vector<int> vector<int>::const_iterator it = nines.begin(); *it = 10; // error: *it is const ++it; // ok: it isn't const so we can change its value
12. the string represents the bit pattern directly. The bits are read from the string from right to left:
(string 對象直接表示爲位模式。從 string 對象讀入位集的順序是從右向左(from right to left):)
string strval("1100"); bitset<32> bitvec4(strval);// ...0001100
一、Arrays have significant drawbacks compared to vectors: They are fixed size, and they offer no help to the programmer in keeping track of how big a given array is. There is no size operation on arrays. Similarly, there is no push_back to automatically add elements. If the array size needs to change, then the programmer must allocate a new, larger array and copy the elements into that new space.(與 vector 類型相比,數組的顯著缺陷在於:數組的長度是固定的,並且程序員沒法知道一個給定數組的長度。數組沒有獲取其容量大小的 size 操做,也不提供 push_back 操做在其中自動添加元素。若是須要更改數組的長度,程序員只能建立一個更大的新數組,而後把原數組的全部元素複製到新數組空間中去。)
二、
C: char largeStr[16 + 18 + 2]; // to hold cp1 a space and cp2 strncpy(largeStr, cp1, 17); // size to copy includes the null strncat(largeStr, " ", 2); // pedantic, but a good habit strncat(largeStr, cp2, 19); // adds at most 18 characters, plus a null
C++: string largeStr = cp1; // initialize large Str as a copy of cp1 largeStr += " "; // add space at end of largeStr largeStr += cp2; // concatenate cp2 onto end of largeStr
(數組類型的變量有三個重要的限制:數組長度固定不變,在編譯時必須知道其長度,數組只在定義它的塊語句內存在。實際的程序每每不能忍受這樣的限制——它們須要在運行時動態地分配數組。雖然數組長度是固定的,但動態分配的數組沒必要在編譯時知道其長度,能夠(一般也是)在運行時才肯定數組長度。與數組變量不一樣,動態分配的數組將一直存在,直到程序顯式釋放它爲止。)
四、It is possible to have a const array of elements of a class type that provides a default constructor:(C++ 容許定義類類型的 const 數組,但該類類型必須提供默認構造函數:)const size_t arr_size = 6; int int_arr[arr_size] = {0, 1, 2, 3, 4, 5}; // ivec has 6 elements: each a copy of the corresponding element in int_arr vector<int> ivec(int_arr, int_arr + arr_size);
The two pointers passed to ivec mark the range of values with which to initialize the vector. The second pointer points one past the last element to be copied. The range of elements marked can also represent a subset of the array:
(傳遞給 ivec 的兩個指針標出了 vector 初值的範圍。第二個指針指向被複制的最後一個元素以後的地址空間。被標出的元素範圍能夠是數組的子集:)
int ival = 42; double dval = 3.14; ival % 12; // ok: returns 6ival % dval; // error: floating point operand
21 % 6; // ok: result is 3 21 % 7; // ok: result is 0 -21 % -8; // ok: result is -5 21 % -5; // machine-dependent: result is 1 or -4 21 / 6; // ok: result is 3 21 / 7; // ok: result is 3 -21 / -8; // ok: result is 2 21 / -5; // machine-dependent: result -4 or -5
(有使用 C 語言背景的讀者可能會以爲奇怪,爲何要在程序中使用前自增操做。道理很簡單:由於前置操做須要作的工做更少,只需加 1 後返回加 1 後的結果便可。然後置操做符則必須先保存操做數原來的值,以便返回未加 1 以前的值做爲操做的結果。對於 int 型對象和指針,編譯器可優化掉這項額外工做。可是對於更多的複雜迭代器類型,這種額外工做可能會花費更大的代價。所以,養成使用前置操做這個好習慣,就沒必要操心性能差別的問題。)
Chapter 6. Statements |
對於 switch 結構,只能在它的最後一個 case 標號或 default 標號後面定義變量:
二、A continue can appear only inside a for, while , or do while loop, including inside blocks nested inside such loops.continue 語句只能出如今 for、while 或者 do while 循環中,包括嵌套在這些循環內部的塊語句中。
三、A block enclosed by the keyword try and one or more catch clauses. If the code inside the try block raises an exception and one of the catch clauses matches the type of the exception, then the exception is handled by that catch. Otherwise, the exception is handled by an enclosing try block or the program terminates.(跟在關鍵字 try 後面的塊,以及一個或多個 catch 子句。若是 try 塊中的代碼產生了異常,並且該異常類型與其中某個 catch 子句匹配,則執行這個 catch 子句的語句處理這個異常。不然,異常將由外圍 try 塊處理,或者終止程序。)
四、
int ival = 512, jval = 1024, kval =4098;
int bufsize;
// ...
switch(swt)
{
case ival :
bufsize = ival * sizeof(int);
break;
case jval:
bufsize = jval * sizeof(int);
break;
case kval:
bufsize = kval * sizeof(int);
break;
}
case 標點中不能使用ival, jval 和kval。由於case 標號中的值只能使用常量表達式,而ival, jval和kval都是變量!
將語句 int ival = 512, jval = 1024, kval =4098;
改成 const int ival = 512, jval = 1024, kval =4098;
Chapter 7. Functions |
返回類型爲 void 的函數一般不能使用第二種形式的 return 語句,可是,它能夠返回另外一個返回類型一樣是 void 的函數的調用結果:
void do_swap(int &v1, int &v2) { int tmp = v2; v2 = v1; v1 = tmp; // ok: void function doesn't need an explicit return } void swap(int &v1, int &v2) { if (v1 == v2) return false; // error: void function cannot return a value return do_swap(v1, v2); // ok: returns call to a void function }
當函數執行完畢時,將釋放分配給局部對象的存儲空間。此時,對局部對象的引用就會指向不肯定的內存。考慮下面的程序:(局部指針也是同樣的!)
// Disaster: Function returns a reference to a local object const string &manip(const string& s) { string ret = s; // transform ret in some way return ret; // Wrong: Returning reference to a local object! }
函數調用的實參按位置解析,默認實參只能用來替換函數調用缺乏的尾部實參。例如,若是要給 background 提供實參,那麼也必須給 height 和 width 提供實參:
screen = screenInit(, , '?'); // error, can omit only trailing arguments screen = screenInit( '?'); // calls screenInit('?',80,' ')
在頭文件中加入或修改 inline 函數時,使用了該頭文件的全部源文件都必須從新編譯。
五、A member function that is defined inside the class is implicitly treated as an inline function.編譯器隱式地將在類內定義的成員函數看成內聯函數。
class Sales_item { public: // operations on Sales_item objects double avg_price() const; bool same_isbn(const Sales_item &rhs) const { return isbn == rhs.isbn; } // private members as before private: std::string isbn; unsigned units_sold; double revenue; }; 中的same_isbn就是內聯函數
六、Each member function (except for static member functions) has an extra, implicit parameter named this. When a member function is called, the this parameter is initialized with the address of the object on which the function was invoked. To understand a member function call, we might think that when we write
每一個成員函數(除了 static 成員函數外)都有一個額外的、隱含的形參 this。在調用成員函數時,形參 this 初始化爲調用函數的對象的地址。爲了理解成員函數的調用,可考慮下面的語句:
total.same_isbn(trans);
it is as if the compiler rewrites the call as
就如編譯器這樣重寫這個函數調用:
// pseudo-code illustration of how a call to a member function is translated Sales_item::same_isbn(&total, trans);
用這種方式使用 const 的函數稱爲常量成員函數。因爲 this 是指向 const 對象的指針,const 成員函數不能修改調用該函數的對象。所以,函數 avg_price 和函數 same_isbn 只能讀取而不能修改調用它們的對象的數據成員。
// pseudo-code illustration of how the implicit this pointer is used // This code is illegal: We may not explicitly define the this pointer ourselves // Note that this is a pointer to const because same_isbn is a const member bool Sales_item::same_isbn(const Sales_item *const this, const Sales_item &rhs) const { return (this->isbn == rhs.isbn); }
八、
void print(const string &); void print(double); // overloads the print function void fooBar(int ival) { void print(int); // new scope: hides previous instances of print print("Value: "); // error: print(const string &) is hidden print(ival); // ok: print(int) is visible print(3.14); // ok: calls print(int); print(double) is hidden }
Normal scoping rules apply to names of overloaded functions. If we declare a function locally, that function hides rather than overloads the same function declared in an outer scope. As a consequence, declarations for every version of an overloaded function must appear in the same scope.
通常的做用域規則一樣適用於重載函數名。若是局部地聲明一個函數,則該函數將屏蔽而不是重載在外層做用域中聲明的同名函數。由此推論,每個版本的重載函數都應在同一個做用域中聲明。
九、 // PF is a pointer to a function returning an int, taking an int* and an int
typedef int (*PF)(int*, int); PF ff(int); // ff returns a pointer to function