读书笔记之:C++Primer 第4版(ch1-11)

第一章 快速入门
1. endl是一个操纵符,它可以刷新与设备相关联的缓冲区。
第二章 变量和基本类型

C++中的保留字

 

1. 初始化和赋值是不同的。
   C++中进行初始化的方法包括复制初始化和直接初始化。
   在内置类型上,这两种方式基本上没有什么差别。
   但是,在自定义的类类型上,还是有很大差别的,有时候只能使用直接初始化。
2. 定义与声明
  定义为变量分配空间,声明向程序表明变量的类型和名字。定义也是声明:当我们定义变量时,我们就声明了它的类型和名字。
  比如:
  extern int i; 这儿是声明但是没有定义i,这儿告诉程序变量i定义在了程序的其他地方。
  int i; 声明并且定义了i,这样一个操作之后程序就为i分配了内存空间。
  如果声明有初始化式,可以被当作定义,即使声明标记了extern
  如:
  extern double pi=3.14; 这儿就是定义了。
  但是需要非常注意的一点是:这中带有extern的定义,只能出现在函数外部。(只有当extern声明位于函数外部时,才可以含有初始化式)
3. 作用域
  全局作用域,局部作用域,语句作用域
4. const对象默认为文件的局部变量(文件链接)这是在C++中,C中是不同的
 在全局定义的非const的变量在整个程序中都可以访问,但是const变量只存在于其定义的文件中,而不能被其他文件访问。
 如果要实现在整个程序中的访问,需要指定const变量为extern。
 如:
 //file1.cpp
 extern const int buf_size=100;
 //file2.cpp
 extern const int buf_size;

 5. 引用是一种复合类型
   引用定义时就必须初始化,并且初始化之后也不能再改变,不允许绑定到另一个对象。
   const引用是指向const对象的引用。  

 

const引用可以初始化为不同类型的对象和初始化为右值,非const引用不能够绑定到右值


第3章标准库类型--string和vector
1. 在头文件中,必须使用完全定义的标准库名字。
2. 默认构造函数
  默认构造函数是在没有显式提供初始化式时所调用的构造函数。它调用的形式是没有任何参数的,所以该构造函数没有任何参数或者所有参数都提供了默认实参。
  如果用户定义的类中没有显式定义任何构造函数,编译器就会自动为该类"合成默认构造函数"。
3.利用cin读取string:cin>>s
   (1)读取并忽略开头所有的空白字符(空格,换行,制表)
   (2)读取字符直至再次遇到空白字符,读取终止。
4. 利用getline读取string
  getline是读取整行文本,但不包含换行符。即便第一个字符就是换行符,getline也停止,此时string对象被置为空。getline(cin,line);
  并且getline不忽略各行开头或其他地方的空格。
5. 迭代器
  容器中的begin和end函数主要用于返回迭代器。begin返回的迭代器指向第一个元素,end返回的迭代器指向容器末端元素的下一个。
  const_iterator可以用于const vector或非const vetor,但是不能够改变元素值。

  而const迭代器初始化之后只能指向它初始化时的元素,不能再指向其他。

 

第4章 数组和指针
1. 指针与引用

★ 相同点:
1. 都是地址的概念;
指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
★ 区别:
1. 指针是一个实体,而引用仅是个别名;
2. 引用使用时无需解引用(*),指针需要解引用;
3. 引用只能在定义时被初始化一次,之后不可变;指针可变;
5. 引用不能为空,指针可以为空;
6. "sizeof 引用"得到的是所指向的变量(对象)的大小,而"sizeof 指针"得到的是指针本身(所指向的变量或对象的地址)的大小;
typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,
但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定)。
7. 指针和引用的自增(++)运算意义不一样;
★ 联系
1. 引用在语言内部用指针实现(如何实现?)。
2. 对一般应用而言,把引用理解为指针,不会犯严重语义错误。引用是操作受限了的指针(仅容许取内容操作)。


2. 指向const对象的指针和const指针
   const指针必须在定义时初始化。
3. 初始化动态分配的数组
  进行动态分配数组时,如果数组元素是类类型,将使用该类型的默认构造函数进行初始化,而如果是内置类型,则不进行初始化。
  如:string *psa=new string[10];//调用string的默认构造函数,元素都初始化为空
     int *pia=new int[10];//不进行初始化
如果在数组长度后面跟一对圆括号,可以要求编译器对数组进行初始化。
  如:
     int *pia=new int[10]();//初始化为0
还要注意的一点是:对于动态分配的数组,其元素只能初始化为元素类型的默认值,而不能像数组变量一样,可以使用初始化列表对数组元素提供不同的初始值。
4. const动态数组
   对于内置类型的const动态数组必须提供初始化值。
   如:
     const int *pci_ok=new const int [10]();//这儿必须加括号
   对于类类型的const动态数组,该类型必须提供默认构造函数,利用默认构造函数进行初始化:
   const string *pcs=new const string[10];
   不过const动态数组无法改变值,所以用处不大。
5. 动态分配空数组。
  在c++中虽然不允许定义长度为0的数组,但是明确指出了调用new动态创建长度为0的数组是合法的:
  char arr[0];//编译错误
  char *cp=new char[0];//合法,但是无法解引用
6. string与C风格字符串
   string和C风格字符串之间牵扯到一个c/c++效率之争的问题,网上讨论很多。
   但是可以肯定的是string的效率是很高的,并且也很安全,所以使用string是不错的。
   注意:C风格的字符串与字符串字面值有相同的数据类型,可以使用字符串字面值的地方就可以使用C风格字符串。

第5章 表达式
1. 隐式类型转换
 这儿值得一提的是关于const对象的转换
 当使用非const对象初始化const对象的引用时,系统将非const对象转换为const对象。此外,还可以将非const对象的地址(或非const指针)转换为指向相关const类型的指针
如:
  int i;
  const int ci=0;
  const int &j=i;
  const int *p=&ci;
2. 显式强制转换
static_cast
dynamic_cast
const_cast:去掉表达式的const性质

reinterpret_cast

第6章 语句

异常处理

 

第7章 函数
1.const形参
尽管函数的形参是const,但是编译器却将函数的定义视为其形参被声明为普通的int型。如:
void fcn(const int i){}
void fcn(int i){}
上面的两个函数是一样的,这主要是为了保持与C的兼容,因为在C中,具有const形参或非const形参的函数并无区别。
2. 通过引用传递数组
如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。在这种情况下,数组的大小成为形参和实参类型的一部分。编译器检查数组实参的大小与形参的大小是否匹配。
如:void printValues(int (&arr)[10]){}
3.指针形参与引用形参
当函数需要处理数组且函数体不依赖于数组的长度的时候应使用指针形参,其他情况下使用引用形参。
4. 默认实参
如果一个形参有默认实参,那么它后面所有的形参都必须有默认实参。默认实参只能用来替换函数调用缺少的尾部实参。
在函数声明或定义中指定默认实参都可以,但是,一个文件中,只能为一个形参指定默认实参一次。
5. const成员函数。
6. 构造函数初始化列表
7. 函数重载
  main函数不能够重载(C++中)
 void f(int,int);
 void f(double,double);
 f(2,2.5);编译的时候会出错,无法判断使用那个函数
 需要类型提升或转换的匹配:对于较小的整型提升为int型,如果一个为int型,另一个为short型,那么对于任意整型的实参值,int版本优于short版本。
 void ff(int);
 void ff(short);
 ff('a')调用ff(int)
 void manip(long);
 void manip(float);
 manip(3.14);编译出错,无法判断,因为double可以向long和float都进行标准转换

枚举类型可以提升为int型或更大的整型。

第8章 IO操作
1. I/O对象不可复制或赋值
 出于某些原因,标准库类型是不允许做复制或赋值操作的。
 (1)只有支持复制的元素类型可以存储在vector或其他容器类型中。由于流对象不能复制,因此不能存储在vector(或其他容器中)
 (2)形参或返回类型也不能是流类型。如果要传递或返回IO对象,则必须传递或返回指向该对象的指针或引用。
2. 标准IO库
头文件              类型
iostream            istream,ostream,iostream
fstream             ifstream,ofstream,fstream 支持open,close操作
sstream             istringstream,ostringstream,stringstream

3. 缓冲区刷新
cout<<"hi"<<flush;不添加任何数据
cout<<"hi"<<ends;添加null
cout<<"hi"<<endl;添加换行

 

第9章 顺序容器
1. 顺序容器主要包括vector,list,deque
2. 指针也是迭代器,所以可以使用内置数组来初始化指针容器
3. 容器中的元素必须满足(1)支持赋值运算(2)可以复制。C++中的大多数类型都满足这个要求,除了引用类型外,所有内置或复合类型都可以做元素类型。
4. 顺序容器的赋值操作
   c1=c2
   c1.swap(c2)交换c1和c2中的内容。

 

5. vector容器的自增长
  为什么一般都比较推荐使用vector呢?因为标准库在实现vector时是这样的内存分配策略:以最小的代价连续存储元素,由此带来的访问元素的便利弥补其存储代价。
  为了使vector容器实现快速的内存分配,其实际分配的容量要比当前所需的空间多一些。vector容器预留了这些额外的存储区,用于存放新添加的元素。
  事实证明,比起list和deque容器,vector的增长效率通常非常高。
6.再谈string
  string具有剧多的insert,assign,和erase操作
  substr(pos,n)操作
  append,replace操作
  find,rfind,find_first_of,find_last_of,find_first_not_of,find_last_not_of

 

  

7.容器适配器:stack,queue,priority_queue
  stack操作:empty(),size(),pop(),top(),push(item)
  queue操作:empty(),size(),pop(),front(),back(),push(item)
  priority_queue:empty(),size(),pop(),top(),push(item)

 

 第10章 关联容器

 

 map,set,multipmap,multiset
1. map容器
可 以定义一个以vecotr<int>::iterator为键关联int型对象,而 不能定义以list<int>::iterator为键关联int型对象,因为vector<int>::iterator支 持<操作,而list<int>::iterator不支持<操作。

2. map与set容器的差别
   map和set的差别在于:map是键-值对的集合,set只是键的集合,map类型适合用于需要了解键与值的对应的情况,例如字典,而set适用于判断某些值是否存在的情况,比如,判断某人的名字是否在黑名单中。
   set和list 的差别在于:set容器中元素不能修改,而list容器中的元素无此限制;set适用于保存值不变的集合,而list容器适用于保存会发生变化的元素。
关联容器map和set的元素是安顺序存储的。

 第11章  泛型算法
1. 泛型算法永远不执行容器提供的操作
  泛型算法本身从不执行容器操作,只是单独依赖迭代器和迭代器操作实现。算法基于迭代器及其操作实现,而非基于容器操作。
2. accumulate算法通过第三个实参来确定累加类型和初值。

posted @ 2012-02-29 12:55  Mr.Rico  阅读(727)  评论(0编辑  收藏  举报