C++prime.docx

上传人:b****7 文档编号:23968097 上传时间:2023-05-23 格式:DOCX 页数:18 大小:27.53KB
下载 相关 举报
C++prime.docx_第1页
第1页 / 共18页
C++prime.docx_第2页
第2页 / 共18页
C++prime.docx_第3页
第3页 / 共18页
C++prime.docx_第4页
第4页 / 共18页
C++prime.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

C++prime.docx

《C++prime.docx》由会员分享,可在线阅读,更多相关《C++prime.docx(18页珍藏版)》请在冰豆网上搜索。

C++prime.docx

C++prime

哦3.C++定义了一组表示整数、浮点数、单个字符和布尔值的算术类型,另外还定义了一种称为void的特殊类型。

void类型没有对应的值,仅用在有限的一些情况下,通常用作无返回值函数的返回类型。

4字符类型有两种:

char和wchar_t。

char类型保证了有足够的空间,能够存储机器基本字符集中任何字符相应的数值,因此,char类型通常是单个机器字节(byte)。

wchar_t类型用于扩展字符集,比如汉字和日语,这些字符集中的一些字符不能用单个char表示。

5.C++中,把负值赋给unsigned对象是完全合法的,其结果是该负数对该类型的取值个数求模后的值。

所以,如果把-1赋给8位的unsignedchar,那么结果是255,因为255是-1对256求模后的值。

6在字符字面值前加L就能够得到wchar_t类型的宽字符字面值。

如:

L'a'

宽字符串

L”awidestringliteral”

7我们可以将任何字符表示为以下形式的通用转义字符:

\ooo

这里ooo表示三个八进制数字,这三个数字表示字符的数字值。

下面的例子是用ASCII码字符集表示字面值常量:

\7(bell)\12(newline)\40(blank)

\0(null)\062('2')\115('M')

8两个相邻的仅由空格、制表符或换行符分开的字符串字面值(或宽字符串字面值),可连接成一个新字符串字面值。

这使得多行书写长字符串字面值变得简单:

//concatenatedlongstringliteral

std:

:

cout<<"amulti-line"

"stringliteral"

"usingconcatenation"

<

:

endl;

Whenexecutedthisstatementwouldprint:

执行这条语句将会输出:

amulti-linestringliteralusingconcatenation

处理长字符串有一个更基本的(但不常使用)方法,这个方法依赖于很少使用的程序格式化特性:

在一行的末尾加一反斜线符号可将此行和下一行当作同一行处理。

,C++的格式非常自由。

特别是有一些地方不能插入空格,其中之一是在单词中间。

特别是不能在单词中间断开一行。

但可以通过使用反斜线符号巧妙实现:

//ok:

A\beforeanewlineignoresthelinebreak

std:

:

cou\

t<<"Hi"<

d:

:

endl;

等价于

std:

:

cout<<"Hi"<

:

endl;

注意反斜线符号必须是该行的尾字符——不允许有注释或空格符。

同样,后继行行首的任何空格和制表符都是字符串字面值的一部分。

正因如此,长字符串字面值的后继行才不会有正常的缩进。

9.在C++中,操作是否合法是在编译时检查的。

当编写表达式时,编译器检查表达式中的对象是否按该对象的类型定义的使用方式使用。

如果不是的话,那么编译器会提示错误,而不产生可执行文件。

10.C++支持两种初始化变量的形式:

复制初始化和直接初始化。

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

intival(1024);//direct-initialization

intival=1024;//copy-initialization

接初始化语法更灵活且效率更高。

11.extern声明不是定义,也不分配存储空间。

事实上,它只是说明变量定义在程序的其他地方。

程序中变量可以声明多次,但只能定义一次。

externinti;//declaresbutdoesnotdefinei

inti;//declaresanddefinesi

只有当extern声明位于函数外部时,才可以含有初始化式。

在C++语言中,变量必须且仅能定义一次,而且在使用变量之前必须定义或声明变量

解释下列例子中name的意义

externstd:

:

stringname;

std:

:

stringname("exercise3.5a");

externstd:

:

stringname("exercise3.5a");

第一条语句是一个声明,说明std:

:

string变量name在程序的其他地方定义。

第二条语句是一个定义,定义了std:

:

string变量name,并将name初始化为:

“exercise3.5a”

第三条语句也是一个定义,但这个语句只能出现在函数外部(即,name是一个全局变量。

12.在对象第一次被使用的地方定义对象可以提高程序的可读性。

读者不需要返回到代码段的开始位置去寻找某一特殊变量的定义,而且,在此处定义变量,更容易给它赋以有意义的初始值。

13.引用是一种复合类型,通过在变量名前添加“&”符号来定义。

复合类型是指用其他类型定义的类型。

在引用的情况下,每一种引用类型都“关联到”某一其他类型。

不能定义引用类型的引用,但可以定义任何其他类型的引用。

因为引用只是它绑定的对象的另一名字,作用在引用上的所有操作事实上都是作用在该引用绑定的对象上:

可以在一个类型定义行中定义多个引用。

必须在每个引用标识符前添加“&”符号:

inti=1024,i2=2048;

int&r=i,r2=i2;//risareference,r2isanint

inti3=1024,&ri=i3;//definesoneobject,andonereference

int&r3=i3,&r4=i2;//definestworeferences

const引用是指向const对象的引用:

constintival=1024;

constint&refVal=ival;//ok:

bothreferenceandobjectareconst

int&ref2=ival;//error:

nonconstreferencetoaconstobject

将普通的引用绑定到const对象是不合法的。

Const引用可以初始化为不同类型的对象或者初始化为右值。

inti=42;

//legalforconstreferencesonly

constint&r=42;

constint&r2=r+i;

但是这种初始化方式对于非const引用确实不合法的,而且会导致编译时错误。

因为:

doubledval=3.14;

constint&ri=dval;

编译器会把这些代码转换成如以下形式的编码:

inttemp=dval;//createtemporaryintfromthedouble

constint&ri=temp;//bindritothattemporary

如果ri不是const,那么可以给ri赋一新值。

这样做不会修改dval,而是修改了temp。

期望对ri的赋值会修改dval的程序员会发现dval并没有被修改。

仅允许const引用绑定到需要临时使用的值完全避免了这个问题,因为const引用是只读的。

注:

非const引用只能绑定到与该引用同类型的对象

const引用则可以绑定到不同但相关的类型的对象或绑定到右值。

17vector是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。

和string对象一样,标准库将负责管理与存储元素相关的内存。

我们把vector称为容器,是因为它可以包含其他对象。

一个容器中的所有对象都必须是同一种类型的。

我们将在第九章更详细地介绍容器。

使用vector之前,必须包含相应的头文件。

#include

usingstd:

:

vector;

vector是一个类模板(classtemplate)。

使用模板可以编写一个类定义或函数定义,而用于多个不同的数据类型。

因此,我们可以定义保存string对象的vector,或保存int值的vector,又或是保存自定义的类类型对象(如Sales_items对象)的vector。

vectorivec;//ivecholdsobjectsoftypeint

vectorSales_vec;//holdsSales_items

vector不是一种数据类型,而只是一个类模板,可用来定义任意多种数据类型。

vector类型的每一种都指定了其保存元素的类型。

因此,vector和vector都是数据类型。

Vector类定义了好几种构造函数,用来定义和初始化vector对象。

Vectorv1:

vector保存类型为T对象。

默认构造函数v1为空。

Vectorv2(v1):

v2是v1的一个副本。

Vectorv3(n,i)v3包含n个值为i的元素。

Vectorv4(n)v4含有值初始化的元素的n个副本

若要创建非空的vector对象,必须给出初始化元素的值。

当把一个vector对象复制到另一个vector对象时,新复制的vector中每一个元素都初始化为原vectors中相应元素的副本。

但这两个vector对象必须保存同一种元素类型:

vectorivec1;//ivec1holdsobjectsoftypeint

vectorivec2(ivec1);//ok:

copyelementsofivec1intoivec2

vectorsvec(ivec1);//error:

svecholdsstrings,notints

可以用元素个数和元素值对vector对象进行初始化。

构造函数用元素个数来决定vector对象保存元素的个数,元素值指定每个元素的初始值:

vectorivec4(10,-1);//10elements,eachinitializedto-1

vectorsvec(10,"hi!

");//10strings,eachinitializedto"hi!

"

vector对象(以及其他标准库容器对象)的重要属性就在于可以在运行时高效地添加元素。

因为vector增长的效率高,在元素值已知的情况下,最好是动态地添加元素。

虽然可以对给定元素个数的vector对象预先分配内存,但更有效的方法是先初始化一个空vector对象,然后再动态地增加元素

如果没有指定元素的初始化式,那么标准库将自行提供一个元素初始值进行值初始化(valueinitializationd)。

这个由库生成的初始值将用来初始化容器中的每个元素,具体值为何,取决于存储在vector中元素的数据类型

如果vector保存内置类型(如int类型)的元素,那么标准库将用0值创建元素初始化式:

vectorfvec(10);//10elements,eachinitializedto0

如果vector保存的是含有构造函数的类类型(如string)的元素,标准库将用该类型的默认构造函数创建元素初始化式:

vectorsvec(10);//10elements,eachanemptystring

还有第三种可能性:

元素类型可能是没有定义任何构造函数的类类型。

这种情况下,标准库仍产生一个带初始值的对象,这个对象的每个成员进行了值初始化。

Vector对象的操作

v.empty()如果v为空,则返回true,否则返回false。

v.size()返回v中元素的个数。

v.push_back(t)在v的末尾增加一个值为t的元素。

v[n]返回v中位置为n的元素。

v1=v2把v1的元素替换为v2中元素的副本。

v1==v2如果v1与v2相等,则返回true。

!

=,<,<=,>and>=保持这些操作符惯有的含义。

Vector的下标操作

vector中的对象是没有命名的,可以按vector中对象的位置来访问它们。

通常使用下标操作符来获取元素。

vector的下标操作类似于string类型的下标操

vector的下标操作符接受一个值,并返回vector中该对应位置的元素。

vector元素的位置从0开始。

下例使用for循环把vector中的每个元素值都重置为0:

//resettheelementsinthevectortozero

for(vector:

:

size_typeix=0;ix!

=ivec.size();++ix)

ivec[ix]=0;

和string类型的下标操作符一样,vector下标操作的结果为左值,因此可以像循环体中所做的那样实现写入。

另外,和string对象的下标操作类似,这里用size_type类型作为vector下标的类型。

下标操作不添加元素

vectorivec;//emptyvector

for(vector:

:

size_typeix=0;ix!

=10;++ix)

ivec[ix]=ix;//disaster:

ivechasnoelements

上述程序试图在ivec中插入10个新元素,元素值依次为0到9的整数。

但是,这里ivec是空的vector对象,而且下标只能用于获取已存在的元素。

这个循环的正确写法应该是:

for(vector:

:

size_typeix=0;ix!

=10;++ix)

ivec.push_back(ix);//ok:

addsnewelementwithvalueix

注:

必须是已存在的元素才能用下标操作符进行索引。

通过下标操作进行赋值时,不会添加任何元素。

18.除了使用下标来访问 vector 对象的元素外,标准库还提供了另一种访问元素的方法:

使用迭代器(iterator)。

迭代器是一种检查容器内元素并遍历元素的数据类型

标准库为每一种标准容器(包括 vector)定义了一种迭代器类型。

迭代器类型提供了比下标操作更通用化的方法:

所有的标准库容器都定义了相应的迭代器类型,而只有少数的容器支持下标操作。

因为迭代器对所有的容器都适用,现代 C++ 程序更倾向于使用迭代器而不是下标操作访问容器元素,即使对支持下标操作的 vector 类型也是这样。

每种容器类型都定义了自己的迭代器类型,如 vector:

vector:

:

iteratoriter;

这条语句定义了一个名为 iter 的变量,它的数据类型是 vector 定义的 iterator 类型。

每个标准库容器类型都定义了一个名为 iterator 的成员,这里的 iterator 与迭代器实际类型的含义相同。

各容器类都定义了自己的 iterator 类型,用于访问容器内的元素。

换句话说,每个容器都定义了一个名为 iterator 的类型,而这种类型支持(概念上的)迭代器的各种操作。

每种容器都定义了一对命名为 begin 和 end 的函数,用于返回迭代器。

如果容器中有元素的话,由 begin 返回的迭代器指向第一个元素:

vector:

:

iteratoriter=ivec.begin();

述语句把 iter 初始化为由名为 vector 操作返回的值。

假设 vector 不空,初始化后,iter 即指该元素为 ivec[0]。

由 end 操作返回的迭代器指向 vector 的“末端元素的下一个”。

“超出末端迭代器”(off-the-enditerator)。

表明它指向了一个不存在的元素。

如果 vector 为空,begin 返回的迭代器与 end 返回的迭代器相同。

由 end 操作返回的迭代器并不指向 vector 中任何实际的元素,相反,它只是起一个哨兵(sentinel)的作用,表示我们已处理完 vector 中所有元素。

迭代器类型定义了一些操作来获取迭代器所指向的元素,并允许程序员将迭代器从一个元素移动到另一个元素。

解引用操作符返回迭代器当前所指向的元素。

假设 iter 指向 vector 对象 ivec 的第一元素,那么 *iter 和 ivec[0] 就是指向同一个元素。

上面这个语句的效果就是把这个元素的值赋为 0。

代器使用自增操作符(1.4.1 节)向前移动迭代器指向容器中下一个元素。

而对迭代器对象则是把容器中的迭代器“向前移动一个位置”。

因此,如果 iter 指向第一个元素,则 ++iter 指向第二个元素。

由于 end 操作返回的迭代器不指向任何元素,因此不能对它进行解引用或自增操作

另一对可执行于迭代器的操作就是比较:

用 == 或 !

= 操作符来比较两个迭代器,如果两个迭代器对象指向同一个元素,则它们相等,否则就不相等。

每种容器类型还定义了一种名为 const_iterator 的类型,该类型只能用于读取容器内元素,但不能改变其值。

当我们对普通 iterator 类型解引用时,得到对某个元素的非 const(2.5 节)。

而如果我们对 const_iterator 类型解引用时,则可以得到一个指向 const 对象的引用(2.4 节),如同任何常量一样,该对象不能进行重写。

使用 const_iterator 类型时,我们可以得到一个迭代器,它自身的值可以改变,但不能用来改变其所指向的元素的值。

可以对迭代器进行自增以及使用解引用操作符来读取值,但不能对该元素赋值。

不要把 const_iterator 对象与 const 的 iterator 对象混淆起来。

声明一个 const 迭代器时,必须初始化迭代器。

一旦被初始化后,就不能改变它的值:

vectornums(10);//numsisnonconst

constvector:

:

iteratorcit=nums.begin();

*cit=1;//ok:

citcanchangeitsunderlyingelement

++cit;//error:

can'tchangethevalueofcit

何时使用 const 迭代器的?

又在何时使用 const_iterator?

解释两者的区别。

const迭代器是迭代器常量,该迭代器本身的值不能修改,即该迭代器在定义时

需要初始化,而且初始化之后,不能再指向其他元素。

若需要指向固定元素的

迭代器,则可以使用const迭代器。

const_iterator是一种迭代器类型,对这种类型的迭代器解引用会得到一个指

向const对象的引用,即通过这种迭代器访问到的对象是常量。

该对象不能修

改,因此,const_iterator类型只能用于读取容器内的元素,不能修改元素的

值。

若只需遍历容器中的元素而无需修改它们,则可以使用const_iterator。

除了一次移动迭代器的一个元素的增量操作符外,vector 迭代器(其他标准库容器迭代器很少)也支持其他的算术操作。

这些操作称为迭代器算术操作(iteratorarithmetic),包括:

∙iter+n

iter–n

∙可以对迭代器对象加上或减去一个整形值。

这样做将产生一个新的迭代器,其位置在 iter 所指元素之前(加)或之后(减) n 个元素的位置。

加或减之后的结果必须指向 iter 所指 vector 中的某个元素,或者是 vector 末端的后一个元素。

加上或减去的值的类型应该是 vector 的 size_type 或 difference_type 类型(参考下面的解释)。

∙iter1-iter2

∙该表达式用来计算两个迭代器对象的距离,该距离是名为 difference_type 的 signed 类型 size_type 的值,这里的 difference_type 是 signed 类型,因为减法运算可能产生负数的结果。

该类型可以保证足够大以存储任何两个迭代器对象间的距离。

iter1 与 iter2 两者必须都指向同一 vector 中的元素,或者指向 vector 末端之后的下一个元素。

可以用迭代器算术操作来移动迭代器直接指向某个元素,例如,下面语句直接定位于 vector 中间元素:

vector:

:

iteratormid=vi.begin()+vi.size()/2;

上述代码用来初始化 mid 使其指向 vi 中最靠近正中间的元素。

这种直接计算迭代器的方法,与用迭代器逐个元素自增操作到达中间元素的方法是等价的,但前者的效率要高得多。

任何改变 vector 长度的操作都会使已存在的迭代器失效。

例如,在调用 push_back 之后,就不能再信赖指向 vector 的迭代器的值了。

19.有些程序要处理二进制位的有序集,每个位可能包含 0(关)1(开)值。

位是用来保存一组项或条件的 yes/no 信息(有时也称标志)的简洁方法。

标准库提供的 bitset 类简化了位集的处理。

要使用 bitset 类就必须包含相关的头文件。

#include

usingstd:

:

bitset;

类似于 vector,bitset 类是一种类模板;而与 vector 不一样的是 bitset 类型对象的区别仅在其长度而不在其类型。

在定义 bitset 时,要明确 bitset 含有多少位,须在尖括号内给出它的长度值:

表 3.6.初始化 bitset 对象的方法

bitsetb;

bhasnbits,eachbitis0

b 有 n 位,每位都 0

bitsetb(u);

bisacopyoftheunsignedlongvalueu

b 是 unsignedlong 型 u 的一个副本

bitsetb(s);

bisacopyofthebitscontainedinstrings

b 是 string 对象 s 中含有的位串的副本

bitsetb(s,pos,n);

bisacopyofthebitsinncharactersfromsstartingfrompositionpos

b 是 s 中从位置 pos 开始的&nbps;n 个位的副本。

bitset<32>bitvec;//32bits,allzero

条语句把 bitvec 定义为含有 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 交通运输

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1