1.迭代器
所有标准库容器都可以使用迭代器,但只有少数容器可以使用下标。
auto b=v.begin(),c=v.endl();//如果容器空,则be都指向尾后迭代器
迭代器支持的运算符,*iter iter->成员,++,--,==,!=//大多数不支持<
vector<int>::iterator iter;
string::iterator it2;//iter可读写元素
vector<int>::const_iterator it;
string::const_iterator it3;//iter不可读写元素
【使用了迭代器的循环体或范围for的循环体都不要向所属的容器添加元素】
支持的运算符+,-,+=,-=,>=,<=,>,<
2.数组
定义时要指定长度
string s[get_size()];//当get_size()是constexpr时正确,否则错误
constexpr sz=42;
int *parr[sz];//含有42个整型指针的数组
字符数组的特殊性char a1={'c','+','+','\0'};//含有显式空字符,没有的话是隐式
【数组不支持拷贝和赋值】
int *(&array)[10]=ptrd;//【由内向外解读】,array是一个引用,引用的对象是一个大小为10的数组
3.指针和数组
string nums[]={"one","two"};
string *p=nums;//与string *p=nums[0]等价,在很多用到数组名字的地方,编译器都会自动地将其替换为一个指向数组首元素的指针
int a[]={0,1,2,3,4};
auto ia2(a);//相当于auto ia2(&a[0]),所以ia2的类型是一个指针int*,指针也是迭代器
标准库begin()和end()函数:int *beg=begin(a);//两个指针相减是它们的距离,即元素数
使用数组初始化vector对象 vector<int> iv(begin(a),end(a));//将a的元素全部赋给iv
vector<int> iv(a+1,a+4);//将a[1],a[2],a[3]赋给iv
4.多维数组是数组的数组
【适用范围for语句处理多维数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型】
int ia[3][4];
for(auto &row:ia)//对于外层数组的每一个元素,要用引用类型的循环变量
for(auto &col:row){//最内层可以不用引用类型的循环变量
col=1;
}
int (*p)[4]=ia;//p指向含有4个整数的数组
可以适当使用类型别名是程序简洁明了
typedef int int_array[4]
for(int_arrat *p=ia;p!=ia+3;p++)//外层循环
5.表达式
拿不准的时候尽量使用括号来确定优先级
若改变了某个运算对象的值,在表达式的其他地方尽量不要再使用该对象
【bool类型不应该参与运算】bool b=true; bool b2=-b;//b2的值还是true!
赋值运算满足右结合律,由右至左
a op=b;<==>a=a op b;
op->mem;<==>(*op).men;
移位运算符满足左结合律
sizeof运算符满足右结合律,不实际计算运算对象的值,返回表达式结果类型的大小
6.隐式类型转换
在以下情况,编译器自动进行类型转换:大多数表达式中,比int类型小的整型值首先提升为较大的整数类型/在条件中非bool值转化为bool类型/初始话过程中初始值转化为变量类型,赋值语句中右侧运算对象转换成左侧运算对象类型/若算术运算或者关系运算的运算对象有多种类型,需要转换为同一种类型/函数调用时
7.显示类型转换
使用const_cast去掉常量属性
cast-name<type>(expression);//当type是转换的目标类型时expression是要转换的值
//当type是引用类型时,结果是左值。【】
double slope=static_cast<double>(j)/i;//进行强制类型转换以便执行浮点数除法,int i,j;
8.switch语句
多个case标签可以对应一个语句:只用一个break语句
switch(ch)
{
case 'a':case 'b':case 'c':case 'd':i++;break;
}
9.范围for语句
for(auto &r:v)//对于v中的每一个元素【范围变量必须是引用类型】
10.异常处理
throw runtime_error(" ");
try{
程序
}catch(异常声明1){处理1}
catch(异常声明2){处理2}
当程序在抛出异常前已经经历了多个try语句块时,寻找处理代码的过程与函数调用的过程刚好相反
标准异常有runtime_error运行时才有的异常 range_error运行时错误:生成的结果超出范围
overflow_error运行时异常计算上溢 underflow_error运行时异常计算下溢
logic_flow程序逻辑错误 domain_error程序逻辑错误参数对应的结果不存在
invalid_argument逻辑错误:无效参数 length_error逻辑错误:试图创建一个超出该类型最大长度的对象
out_of_range逻辑错误,使用一个超出有效范围的值
11.函数调用
static变量在函数调用结束后依然有效
函数声明也叫做函数原型
分离式编译,如果修改了其中一个源文件那么只需要重新编译该文件就可以
如果形参是引用类型{称对应的实参被引用传递或者函数被传引用调用},它将绑定到对应的实参上,否则将实参的值拷贝后赋给形参。【建议使用引用类型的形参代替指针】
有些类型不支持拷贝操作,可以用引用访问,引用形参为一次返回多个结果提供了可能。
void fcn(const int i); 【fcn可以读取但不能写入i】
void fcn(int i);【错误,重复定义】
在定义函数形参和变量时将不会改变的类型定义位const
void print(const int[10]) //这里的维度表示我们期望数组含有多少个元素实际上不一定
防止数组越界有三种常用技术:1使用标记指定数组长度while(*cp) //cp不是空
2.使用标准库规范 while(beg!=end){beg++;//}
3.显式地传递一个表示数组长度地形参
main处理命令行选项
int main(int argc,char *argv[]){}
或者int main(int argc,char **argv){} //第一个参数是数组中字符串的数量,第二个参数是字符串数组,当使用argv中的实参时 要记得可选的实参从argv[1]开始,argv[0]保存程序的名字
省略符形参initializer_list[定义在同名的文件中]形参可以传递类型相同数量可变数量的形参,但是这种功能一般只用于与c函数交互的接口程序。大多数类类型的对象在传递给省略符形参时都无法正确拷贝。
eg:错误输出函数
void error_msg(initializer_list<string> il,int i){//含有initializer_list类型形参也可以同时有其他形参
for(auto beg=il.begin;beg!=il.end();beg++)
cout<<*beg<<endl;
}
无返回值函数在执行到中间位置时可以使用return;提前退出【不要返回局部对象的引用或指针,因为函数种植意味着局部变量的引用将指向不再有效的内存区域 】允许main函数没有return函数直接结束
函数可以返回花括号包围的值的列表
如果形参是某种类型的指针或引用,则通过区分其指向的是常量对象还是非常量对象可以实现函数重载。
void lookup(Account&)
void lookup(const Account&)//作用于常量引用
void lookup(Account*)//作用于指向Account的指针
void lookup(const Account*)//作用于指向常量的指针
【如果在内层作用域中声明名字(变量或函数名,比如内层声明bool read=false;外层的
read函数将无法使用),它将隐藏外层作用域中的同名实体,在不同的作用域中无法重载函数名】
string screen(sz ht=24,sz wid=80,char bg=' ');//如果想使用默认是参,只要在调用函数的时候省略该实参就可以了,函数调用时实参按其位置解析,【默认实参负责填补函数调用缺少的尾部实参】;
window=screen('?')//相当于调用了window=screen('?',80,' ')会将字符?的ASCII码值传给ht
所以设置默认实参时尽量让不怎么使用默认值的形参出现在前面,让使用默认值的形参出现在后面。
一般一个函数只声明一次但多次声明也是合法的,【在给定的作用域中一个形参只能被赋予一次默认值,即函数的后续声明只能为之前那些没有默认值的形参添加默认实参,而且该形参右侧的所有形参必须都有默认值】
如果表达式的类型可以转换为形参所需的类型,那么表达式的值也可以做默认实参
12.inline内联函数和constexpr函数
调用函数一般比求等价表达式的值慢一些,内联函数可以避免函数调用的开销
比如 inline const string & shorterString(const string s1,const string s2){return s1.size()<=s2.size()?s1:s2}
【内联机制用于优化规模较小流程直接频繁调用的函数,内联只是向编译器发出的一个请求,编译器可以选择忽略】
constexpr函数只能用于常量表达式的函数:函数的返回类型及所有形参的类型都必须是字面值类型比如 return 42;允许constexpr函数的返回值并非一个常量,常量表达式也可以foo(2)ok,foo(i)不可
【内联函数和constexpr函数通常定义在头文件中】
13.assert宏和NDEBUG预处理
#include <cassert>
assert(表达式);//不需要using或者std::
如果定义了NDEBUG不会执行运行时检查,此时arrset什么也不做,可以辅助调试
14.函数指针
要想声明一个可以指向某函数的函数指针,只需要用指针替换函数名即可
bool (*pf)(const string &,const string &);//【*pf两端的括号不可省,没有括号会被认为是bool*类型的函数】
pf=lengthCompare;//pf指向名为lengthCompare的函数,形参类型要匹配·
pf=&lengthCompare;//与上句等价,&是可选的
此外还可以直接使用指向函数的指针调用该函数,无需提前解引用指针,一下三个调用是等价的
bool b1=pf("he","gb");
bool b2=(*pf)("he","gb");
bool b3=lengthCompare("he","gb");
pf=0;//该指针未指向任意一个函数
函数指针也可以作为另一个函数的形参或者返回值,如果形参是函数名,会自动转换为函数指针