從「林」開始--C++ primer 讀書筆記 -- Part1: The Basics

從「林」開始--C++ primer 讀書筆記 -- Part1: The Basics

【持續更新ing】
#####################################
//聲明:1: 本文根據本身閱讀的重點記錄而已
//          2:筆記基本都是從《C++ Primer第四版中英文對照.chm》複製而來!
//          3:歡迎拍磚
//          4:同上
#####################################

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;
      }

The name ‘val’ is more interesting. It is defined in the scope of the for statement. It can be used in that statement but not elsewhere in main. It has statement scope.(名字 val 更有意思,它定義在 for 語句的做用域中,只能在 for 語句中使用,而不能用在 main 函數的其餘地方。它具備 語句做用域。)

7:The operations supported by a type. Well-designed classes separate their interface and implementation, defining the interface in the public part of the class and the implementation in the private parts. Data members ordinarily are part of the implementation. Function members are part of the interface (and hence public) when they are operations that users of the type are expected to use and part of the implementation when they perform operations needed by the class but not defined for general use.
(由某種類型支持的操做。設計良好的類分離了接口和實現,在類的 public 部分定義接口, private 部分定義實現。數據成員通常是實現的一部分。當函數成員是指望該類型的使用者使用的操做時,函數成員就是接口的一部分(所以爲 public);當函數成員執行類所須要的、非通常性使用的操做時,函數成員就是實現的一部分)

 
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 語句)的條件內定義。

延伸: 按存儲區域分,全局變量、靜態全局變量和靜態局部變量都存放在內存的靜態存儲區域,局部變量存放在內存的棧區。

      按做用域分,全局變量在整個工程文件內都有效;靜態全局變量只在定義它的文件內有效;靜態局部變量只在定義它的函  數內有效,只是程序僅分配一次內存,函數返回後,該變量不會消失;局部變量在定義它的函數內有效,可是函數返回後失效。


Chapter 3. Library Types

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.(兩種最重要的標準庫類型是 stringvectorstring 類型支持長度可變的字符串,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 個副本


3. The newline that causes getline to return is discarded; it does not get stored in the string.

(因爲 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

保持這些操做符慣有的含義


5. string substr = "Hello";

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 operand 

string 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.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

Chapter 4. Arrays and Pointers

一、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

三、A variable of array type has three important limitations: Its size is fixed, the size must be known at compile time, and the array exists only until the end of the block in which it was defined. Real-world programs usually cannot live with these restrictionsthey need a way to allocate an array dynamically at run time. Although all arrays have fixed size, the size of a dynamically allocated array need not be fixed at compile time. It can be (and usually is) determined at run time. Unlike an array variable, a dynamically allocated array continues to exist until it is explicitly freed by the program.

(數組類型的變量有三個重要的限制:數組長度固定不變,在編譯時必須知道其長度,數組只在定義它的塊語句內存在。實際的程序每每不能忍受這樣的限制——它們須要在運行時動態地分配數組。雖然數組長度是固定的,但動態分配的數組沒必要在編譯時知道其長度,能夠(一般也是)在運行時才肯定數組長度。與數組變量不一樣,動態分配的數組將一直存在,直到程序顯式釋放它爲止。)

四、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 初值的範圍。第二個指針指向被複制的最後一個元素以後的地址空間。被標出的元素範圍能夠是數組的子集:)


Chapter 5. Expressions

一、     
         int ival = 42;      double dval = 3.14;
     ival % 12;   //  ok: returns 6 

ival % 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 


二、 關於位移的延伸:
     左移裏一個比較特殊的狀況是當左移的位數超過該數值類型的最大位數時,編譯器會用左移的位數去模類型的最大位數,而後按餘數進行移位,如:

int i = 1, j = 0x80000000; //設int爲32位
i = i << 33;   // 33 % 32 = 1 左移1位,i變成2
j = j << 33;   // 33 % 32 = 1 左移1位,j變成0,最高位被丟棄 

三、Readers from a C background might be surprised that we use the prefix increment in the programs we've written. The reason is simple: The prefix version does less work. It increments the value and returns the incremented version. The postfix operator must store the original value so that it can return the unincremented value as its result. For ints and pointers, the compiler can optimize away this extra work. For more complex iterator types, this extra work potentially could be more costly. By habitually favoring the use of the prefix versions, we do not have to worry if the performance difference matters.

(有使用 C 語言背景的讀者可能會以爲奇怪,爲何要在程序中使用前自增操做。道理很簡單:由於前置操做須要作的工做更少,只需加 1 後返回加 1 後的結果便可。然後置操做符則必須先保存操做數原來的值,以便返回未加 1 以前的值做爲操做的結果。對於 int 型對象和指針,編譯器可優化掉這項額外工做。可是對於更多的複雜迭代器類型,這種額外工做可能會花費更大的代價。所以,養成使用前置操做這個好習慣,就沒必要操心性能差別的問題。)

Chapter 6. Statements

一、Variables can be defined following only the last case or default label:

    對於 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

一、A function with a void return type ordinarily may not use the second form of the return statement. However, a void function may return the result of calling another function that returns void:

返回類型爲 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      
     }


二、When a function completes, the storage in which the local objects were allocated is freed. A reference to a local object refers to undefined memory after the function terminates. Consider the following 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!      
     }


三、Arguments to the call are resolved by position, and default arguments are used to substitute for the trailing arguments of a call. If we want to specify an argument for background, we must also supply arguments for height and width:

函數調用的實參按位置解析,默認實參只能用來替換函數調用缺乏的尾部實參。例如,若是要給 background 提供實參,那麼也必須給 height 和 width 提供實參:

screen = screenInit(, , '?'); // error, can omit only trailing arguments      
     screen = screenInit( '?');    // calls screenInit('?',80,' ')

四、Whenever an inline function is added to or changed in a header file, every source file that uses that header must be recompiled.

在頭文件中加入或修改 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);

七、A function that uses const in this way is called a const member function. Because this is a pointer to const, a const member function cannot change the object on whose behalf the function is called. Thus, avg_price and same_isbn may read but not write to the data members of the objects on which they are called.

用這種方式使用 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

Chapter 8. The IO Library

一、

相關文章
相關標籤/搜索