说明:
ri引用了一个整形的数,对ri的操作应该是整形操作运算,单是dval却是双精度浮点数。
中间生成临时变量3,就是对3的常量引用。
当通过这个引用改变dval的值时就无法改变,这种引用非法。
2.4.2指针和const
指向常量的指针------不能更改其所指的对象
constdoublepi=3.14;//pi为一个常量
//double*ptr=π//错误,ptr为一个普通的指针(所谓类型一致)
constdouble*cptr=π//cptr可以指向一个双精度的常量的指针
//*cptr=42;//错误,不能给*cptr赋值
说明:
指针的类型必须和所指的类型一致。
有两个特列,一种特列情况是:
允许另一个指向常量的指针指向一个非常量的对象。
doubledval=3.14;
cptr=&dval;
另一种:
指向常量的指针也没有也没有规定其所指的对象必须是一个常量。
Const指针
常量指针必须初始化,一但初始化,它里面存放指针的地址就不会改变,一直指向一个对象。
intNum=0;
int*constp=&Num;//p一直指向Num(顶层const)
cosntdoublepi=3.14;
constdouble*constpip=π//pip是一个指向常量对象的常量指针
说明:
指针本身是不是常量并不意味着不能通过指针修改其所指对象的值,能否这样做完全依赖于所指对象的值。
2.4.3顶层const(需要看P59页)
顶层const(top-levelconst):
指针本身是个常量。
底层const(low-levelconst):
指针所指的对象是一个常量
inti=0;
int*constp1=&i;//不能更改p1的值,p1一直指向i(顶层cosnt)
cosntintci=42;//不能更改ci,(顶层cosnt)
constint*p2=&ci;//允许改变p2的指向,(底层const)
constint*constp3=p2;//靠右的为(顶层const),靠左的为(底层cosnt)
constint&r=ci;//用于声明引用的都是底层const
当指向拷贝操作,顶层不受影响
底层受到限制
2.4.4constexpr和常量表达式
常量表达式:
在编译过程中就能的计算结果的表达式(字面值,cosnt);
Constexpr-----C11规定,允许将变量声明为cosntexpr类型以便由编译器来验证变量的值是不是一个表达式。
注意:
声明为cosntexpr的变量一定是个常量,必须使用常量表达式初始化。
constexprintf=20;//20是常量表达式
constexprintlimit=mf+1;//mf+1是常量表达式
constexprintsz=size();//只有当size是一个consexpr函数时才是一个正确的声明语句
指针和constexpr---------------在constexpr声明中如果定义一个指针,限定符constexpr仅仅对指针有效,与指针所指的对象无关:
constint*p=nullptr;
constexprint*q=nullptr;
说明:
p是一个指向常量的指针,而q是一个常量指针,其中关键在与constexpr把它定义的对象设置为顶层cosnt.
与其他常量指针类似,constxepr指针既可以指向常量也可以指向一个非常量。
2.5处理类型别名
两种方法;
传统方法:
typedef
typedefdoublewages;
typedefwagesbase,*p;
新标准:
使用别名声明(aliasdeclaration)
usingSi=Sqles_item;
指针.常量和类型别名(这里需要多看,才能理解)
如果某个类型别名指代的是复合类型或者常量,那么把它用到声明语句就会产生意想不到的结果。
typedefchar*pstring;
constpstringcstr=0;
constpstring*ps;
说明:
两条声明语句的基本类型都是constpstring,const是对给定类型的修饰。
Pstring实际上是指向char的指针,因此,constpstring就是指向char的常量指针,而非指向常量字符的指针。
constchar*cstr=0;//是对constpstringcstr的错误理解
强调:
这种理解错误。
声明语句中用到pstring时,其基本数据类型是指针。
可是用char*重写了声明语句后,数据类型就成了char,*成了声明符的一部分。
这样改写的结果是,constchar成了基本数据类型。
前后两种结果截然不同,前者生命了一个指向char的常量指针,改写后的形式则声明了一个指向constchar的指针。
inti=0;
int*constp1=&i;//这是常量指针,常量指针必须本初始化,始终指向一个对象的地址,(有点像引用)
针来修改变量的值
constintj=0;
constint*constp2=&i;//指向常量对象的常量指针可以指向普通变量,但也必须初始化
constint*constp3=&j;//p3是一个指向常量对象的常量指针,只要是常量指针必须被初始化
//可以通过常量指针修改变量的值,但是不可以令常量指针再指向其他对象
//p2=&j;//这样就是错误的
constint*p4;//指针常量,可以不必初始化,可以指向多个对象
p4=&i;
p4=&j;
//*p4=5;//这就是错误的,不能通过指
//consttextp5=0;//错误,如果只是简单的认为把text替换成int*,那就打错特错了,
constint*p5;//正确,如果只是简单的认为
consttext*ps;//ps是一个指针,它的对象是指向int的常量指针
//int*cosnt*ps;
typedefchar*pstring;
constpstringcstr=0;//cstr是指向char的常量指针
constpstring*ps;//ps是一个指针,它的对象是指向char的常量指针
2.5.2auto类型说明符
C++11新标准引入了auto’类型说明符,用它就能让编译器替我们去分析表达式的所属的类型;auto让编译器通过初始值来推断变量类型。
显然,auto定义的变量必须初始值。
autoitem=val1+val2;//item定义的变量必须有初始值
复合类型常量和auto
Auto一般会忽略顶层const,同时底层const则会保留下来。
例如:
constintci=i,&cr=ci;
autob=ci;//b是一个整数(ci的顶层const特性被忽略掉了)
autoc=cr;//c是个整数(cr是ci的别名,ci本身是一个顶层const)
autod=&i;//d是一个整数的指针(整数的地址就是指向整数的指针)
autoe=&ci;//e是一个指向整数常量的指针(对常量对象取地址是一种底层const)
如果希望推断出的auto类型是一个顶层const,需要指明:
Constautof=ci;
还可以设置引用类型为auto,
auto&g=ci;
auto&h=42;
cosntauto&j=42;
2.5.3decltype类型指示符
C++11新标准引入了第二中类型说明符decltype,它的作用是选择并返回操作数的数据类型。
在此过程中,编译器分析表达式并的它的类型,却不实际计算表达式的值。
decltype(f())sunm=x;//sum的类型就是函数f的返回类型
decltype处理顶层cosnt和引用的方式与auto有些方式不同。
constintci=0,&ci=ci;
decltype(ci)x=0;//x的类型是cosntint
decltype(cj)y=x;//y的类型cosntint&,y绑定到变量x
decltype(cj)z;//错误:
z是一个引用,必须初始化
decltype和引用----(这里看不懂)------P63页
2.6自定义的数据结构
第3章字符串,向量,和数组
3.1命名空间的using声明
3.2标准库类型string
3.2.1定义和初始化string对象
strings1;//默认初始化,s1是一个空的字符串
strings2=s1;//s2是s1的一个副本
strings3="hiya";//s3是该字符串字面值的副本
strings4(10,'c')//s4的内容是10个c
直接初始化----------不使用=
拷贝初始化-----------使用=
strings5="hiya";//拷贝初始化
strings6("hiya");//直接初始化
strings7(10,'c');//直接初始化,
strings8=string(10,'b');//创建一个临时对象进行拷贝
3.2.2string对象的操作
strings;//空字符串,
cin>>s;//将string对象读入s,遇到空白停止
cout<
说明:
输入“HelloWorld”,输出是“Hello”,输出没有空格。
即就是输入开始的空格不计,再遇到空格结束。
strings1,s2;//空字符串,
cin>>s1>>s2;//将string对象读入s,遇到空白停止
cout<说明:
输入“HelloWorld”,输出“Hello”,输出的是“HelloWorld”
使用getline读取一整行
stringline;
while(getline(cin,line))
cout<return0;
return0;
string的empty和size操作
string:
:
size_type类型
在C++11新标准中,允许编译器通过auto或者decltype来推断变量的类型
autolen=line.aize();///len的类型是string:
:
size_type
比较string对象
字面值和string对象的相加
strings1="hello",s2="world";
strings3=s1+","+s2;
cout<当把string对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符(+)的两侧的运算对象至少有一个是string:
strings1="hello",s2="world";
strings3=s1+","+s2;
cout<strings4=s1+',';
strings10=","+s1;//这样也正确
//strings5="Hello"+",";//两个运算对象不是string
strings6=s1+","+"world";//‘
//strings7="hello"+","+s2;///不能把字面值直接相加
stringtmp=s1+",";//
s6=tmp+"world";//
strings8=("hello"+",")+s2;//不能把字面值直接相加
注意:
C++中字符串字面值并不是标准库中类型string的对象。
字符串字面值和string是不同的类型。
3.2.3处理string对象的字符
3.3标准库类型vector
Vector是模板而非类型,有vector生成的类型必须包含vector中元素的类型,
3.3.1定义和初始化vector对象
vectorsvec;//默认初始化,svec不含任何元素
vectorivec;
vectorivec2(ivec);//把ivec的元素拷贝给ivec2
vectorivec3=ivec;//把ivec的元素拷贝给ivec3
列表初始化vector对象
vectorarticles={"a","an","the"};
vectorv1{"a","an","the"};//列表初始化
创建指定数量的元素
vectorivec(10,-1);//10个int类型的元素,每个元素赋值为-1
vectorsvec(10,"Hi");//
值初始化---可以只提供vector对象容纳的元素数量而
vectorivec(10);//10个元素,每个元素初始化为0
vectorsvec(10);//10个元素,每个都是空的字符串对象
3.3.2向vector对象中添加元素
vectorv2;//空的vector对象
for(i=0;i<100;++i)
v2.push_back(i);//依次把整数值放入末尾
stringword;
vectortext;
while(cin>>word)
text.push_back(word);
3.3.3其他vector操作-------91页表3.5
vectorv{1,2,3,4,5,6};
for(auto&i:
v)//对于v中的每个元素,元素i为引用
i*=i;//求元素的平方
for(autoi:
v)//对于v中的每个元素
cout<
cout<不能通过下标形式添加元素
vectorivec;
//for(decltype(ivec.size())ix=0;ix!
=10;++ix)
//ivec[ix]=ix;//可以通过编译,但是不能运行
for(decltype(ivec.size())ix=0;ix!
=10;++ix)
ivec.push_back(ix);
注意:
vector对象的下标运算符可用于访问已存在的元素,而不能用于添加元素
3.4迭代器介绍
3.4.1使用迭代器
//由编译器决定,b和e的类型
//b表示v的第一元素,e表示v末元素的下一个位置
vectorv;
autob=v.begin(),e=v.end();
注意:
如果容器为空,则begin和end返回的是同一容器,都是尾后迭代器
迭代器运算符
strings("somestring");
if(s.begin()!
=s.end())//确保s非空
{
autoit=s.begin();//it表示s的第一个字符
*it=toupper(*it);//将当前字符改成大写形式
cout<<*it;
}
将迭代器从一个元素移到另外一个元素
strings("somestring");
for(autoi=s.begin();i!
=s.end();++i)
*i=toupper(*i);//当前字符改成大写形式
cout<
再加上条件!
isspace(*i)就会只是第一个单词变成大写形式
迭代器的类型----实际上使用iterator和const_iterator来表示迭代器的类型:
vector:
:
iteratorit;//it能读写vector的