从「林」开始--C++ primer 读书笔记 -- Part1: The Basics

从「林」开始--C++ primer 读书笔记 -- Part1: The Basics

【持续更新ing】
#####################################
//声明:1: 本文根据自己阅读的重点记录而已
//          2:笔记基本都是从《C++ Primer第四版中英文对照.chm》复制而来!
//          3:欢迎拍砖
//          4:同上
#####################################

Chapter 2. Variables and Basic Types


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

    (复制初始化语法用等号(=),直接初始化则是把初始化式放在括号中):  

      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

    (每个类都可能会定义一个或几个特殊的成员函数来告诉我们如何初始化类类型的变量。定义如何进行初始化的成员函数称为构造函数)


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 变量为空字符串,即没有字符的字符串:)

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:

程序的一部分,在其中名字有意义。C++ 含有下列几种作用域:

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

Chapter 4. Arrays and Pointers

1、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 操作在其中自动添加元素。如果需要更改数组的长度,程序员只能创建一个更大的新数组,然后把原数组的所有元素复制到新数组空间中去。)

2、 

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

3、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.

(数组类型的变量有三个重要的限制:数组长度固定不变,在编译时必须知道其长度,数组只在定义它的块语句内存在。实际的程序往往不能忍受这样的限制——它们需要在运行时动态地分配数组。虽然数组长度是固定的,但动态分配的数组不必在编译时知道其长度,可以(通常也是)在运行时才确定数组长度。与数组变量不同,动态分配的数组将一直存在,直到程序显式释放它为止。)

4、It is possible to have a const array of elements of a class type that provides a default constructor:(C++ 允许定义类类型的 const 数组,但该类类型必须提供默认构造函数:)

5、

          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

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


2、 关于位移的延伸:
     左移里一个比较特殊的情况是当左移的位数超过该数值类型的最大位数时,编译器会用左移的位数去模类型的最大位数,然后按余数进行移位,如:

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,最高位被丢弃 

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

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

    对于 switch 结构,只能在它的最后一个 case 标号或 default 标号后面定义变量:

2、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 循环中,包括嵌套在这些循环内部的块语句中。

3、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 块处理,或者终止程序。)

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

1、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      
     }


2、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!      
     }


3、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,' ')

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

在头文件中加入或修改 inline 函数时,使用了该头文件的所有源文件都必须重新编译。

5、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就是内联函数


6、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);

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


8、

     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.

一般的作用域规则同样适用于重载函数名。如果局部地声明一个函数,则该函数将屏蔽而不是重载在外层作用域中声明的同名函数。由此推论,每一个版本的重载函数都应在同一个作用域中声明。

9、    // 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

1、

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://my.oschina.net/wuying/blog/51325

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值