容易忘记的部分:
2.1:C++提供的几种字符串类型有哪些及其用途?
基本的字符类型char,一个char的类型和一个机器字节一样
其他字符类型用于拓展字符集,如wchar_t、char16_t、char32_t
wchar_t类型确保可以存放机器最大拓展字符集中的任意一个字符
char16_t和char32_t则为Unicode字符集服务
2.2:如何选择所使用的类型
当数值不为负数时,使用无符号类型(unsigned)
一般常用int和long long执行整数的运算
算术表达式中不使用char和bool,只有在特定的时候才使用特定的类型(char:存放字符,bool:存放布尔值)
使用字符时最好明确指出是signed char还是unsigned char
执行浮点数运算时选用double
2.3:字符类型转换中需要注意的问题
无符号类型:
1.当赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的取数。例如8bit的unsigned char表示[0,255]内的数,把-1赋值给它得到255
2.如果表达式里既有带符号类型又有无符号类型,那么带符号类型会自动转化为无符号类型,表达式的结果不会有负数的存在
带符号类型:
1.当赋给带符号类型一个超出表示范围的数,结果是未定义的
2.4:字面值常量相关内容
1.以0开头的代表8进制,0x/0X开头的代表16进制。整型字面值的具体类型由它的值和符号决定。
2.字符串字面值是由常量字符构成的数组
3.转移字符,具体有哪些转移字符及其表示见书P62
4.我们可以通过添加前缀或者后缀来指定字面值的类型,具体的前缀、后缀见书P63
2.5:什么是对象?
对象是指一块能存储数据某种类型的存储空间,一般把命名了的对象叫做变量,而把变量中存的数据叫做值
2.6:初始化的相关事项
1.初始化不是赋值,初始化是创建变量时赋予一个初始值,而赋值是把对象当前的值移除,用新的值来替代
2.列表初始化不能用于可能存在初始值丢失的情况(如用浮点数对整型进行列表初始化)
3.默认初始化:对于内置类型来说,当定义的变量在函数外时,默认初始化为0,若定义的变量来函数内时,变量不被初始化。对于类来说,默认值只与类的构造函数有关,与位置无关
2.7:声明和定义的区别
声明使得名字被程序知道,一个文件想用别人定义的名字必须包含对那个名字的声明
定义负责创建于名字相关的实体。除了规定变量的类型和名字,还会申请存储空间,也有可能赋予初始值
显示声明:在类型前添加关键词extern。如果存在初始化,则视为定义
如果要在多个文件中使用一个变量,变量只能被定义一次,但是可以被声明多次
2.8:标识符的命名规则
标识符(变量名/函数名.....)由字母、数字和下划线组成,其中必须以字母或者下划线开头,长度没有限制,但是对大小写敏感。通常不要使用下划线开头的标识符,因为标准库实现的名字均以下划线开头。
命名规范:
1.能体现实际含义
2.变量名一般用小写字母
3.用户自定义的类名用大写字母开头
4.如果标识符由多个单词组成,则单词间应用下划线分开
注意不要使用C++中的关键词和操作替代名(具体有哪些见书P43)
2.9:相同变量名的不同作用域覆盖问题
名字的有效区域始于名字的声明语句,以声明语句所在的作用域末端为结束
当一个变量在它所嵌套的作用域下又被定义了一次,则在新建变量的作用域下,新建的变量值会覆盖老的变量值,如果想要访问老的变量值,则需要使用作用域符::,当作用域符的左侧为空时,获得全局作用域下老的变量值。
建议:当第一次使用变量在定义它,并且局部变量最好不要和全局变量同名
2.10:生成空指针的办法
1.用字面值nullptr来初始化指针,nullptr作为一种特殊的字面值可以被转换为任意其他指针类型(推荐使用)
2.用字面值0来初始化
3.用一个名为NULL的预处理变量来给指针赋值,这个变量定义在头文件cstdlib中,值为0(避免使用)
2.11:指针值有哪些
1.指向一个对象
2.指向紧邻对象所占空间的下一个位置
3.空指针,没有指向任何对象
4.无效指针,即上述情况之外的其他值
2.12:const限定符
const只能限定对象,因此没有const引用,但是有引用const对象的引用
对象的类型决定了其上的操作。const类型的对象和非const对象类型相比的不同在于:
1.不能改变对象的内容
2.const对象必须初始化
要想在文件之间共享const变量,解决的办法是不管是声明还是定义都添加extern关键字
2.13:constexpr和常量表达式
常量表达式:值不会改变,且在编译过程就能得到计算结果的表达式。一个对象/表达式是否为常量表达式由其对象(const)和初始值(常量表达式)决定
允许将变量声明为constexpr类型以便由编译器来验证变量是否是常量表达式。要求声明constexpr的变量一定是一个常量,同时必须要用常量表达式进行初始化,以及声明要用到的类型必须是字面值类型(内置类型,不包括标准库和自己定义的类类型)
虽然指针和引用都能定义为constexpr,但是因为constexpr的初始值必须是常量,所以对于指针来说,只有当其的初始值为nullptr或者指向某个固定地址(只能是在函数外定义,不能在函数内定义。或者是:允许函数定义一类有效范围超出函数本身的变量)才可以。而对于一个constexpr指针来说,constexpr只修饰指针本身,是一个顶层const,constexpr位于声明最开始的地方
2.14:两种处理类型别名的办法
使用关键词typedef和关键词using(别名声明)
typedef double wages;
using SI=Sales_item;
2.15:auto类型说明符
auto的原理:通过初始值来推断变量的类型。因此auto定义的变量必须要有初始值
如果使用auto在一条语句声明多个变量,要确保证明语句中变量的数据类型相同
auto会忽略顶层const,保留底层const。因此如果希望推断出顶层const,必须自己明确指出
2.16:decltype类型指示符
decltype的作用是选择并返回操作数的数据类型,在这个过程中,它不计算表达式结果,只得到它的类型。
decltype会保留顶层const,此处与auto不同。
引用从来都作为其引用对象的别名出现,而只有在decltype中例外,decltype(引用),会返回一个引用类型,同时注意此处必须初始化
需要理解的部分:
2.1:内置类型的机器实现是怎么样的?
(详细解释见书P57)一个类型的对象占据一定的字节大小。对于一个地址,我们只有知道了存储在该地址的数据的类型,才能知道该内存空间的明确含义
2.2:引用
我们这里的引用指的是左值引用,而右值引用主要用于内置类
因为引用本身不是一个对象,所以不存在引用的引用。
于此同时,引用的类型要和与之绑定的对象严格匹配,不能于某个字面值绑定在一起
2.3:指针
指针本身是对象,并且指针也只能指向对象(即不存在指向引用的指针)
指针的类型要和它所指的对象严格匹配
指针的解引用操作只适用于那些确实指向了某个对象的有效指针
不能把int变量直接赋值给指针(但是可以把字面值0赋值给指针)
建议定义了对象之后再定义指向它的指针,同时建议初始化所有指针,如果不清楚指针指向哪里,就初始化为nullptr或0
想要搞清一条赋值语句改变的是指针的值还是指针所指对象的值,记住赋值改变的永远是等号左侧的对象
永远记住指针存的是地址,当拿指针参与运算时(一定要确保指针是有效的指针)。如果是条件判断,则看指针是否指向一个对象。如果是判断指针是否相等,则看指针所保存的地址是否相等即可。
2.4:指针和引用的不同
1.指针本身是对象。而引用只是其他对象的别名,和其他对象绑定在一起。
2.指针可以先后指向多个不同的对象,允许指针赋值和拷贝。而引用不能更改绑定对象。
3.指针无需在定义时赋值,其默认初始化和内置类型相同。而引用在定义时一定要确定其引用的对象,所以必须初始化。
2.5:某些符号有多重含义
像&和*,既能作为表达式里的运算符,也能作为声明语句中的一部分出现。由符号出现的位置决定了符号的意义。
当&和*紧随类型名出现时,符号是声明的一部分;而当符号出现在表达式中时,它们又转变成了运算符
2.6:void*指针
是一种特殊指针,可以存放任意对象的地址。
但因为我们不知道它所指对象的类型,所以不能通过解引用对所指对象进行操作。
但它可以作指针本身的操作:和其他指针比较、作为函数输入/输出,赋值给另一个void*指针
2.7:符合类型的声明
1.类型修饰符(*和&)只作用于单个对象。对于int *p,其基本类型是int,不是int*。*仅仅修饰了对象p,不对其他对象产生任何的作用
2.类型修饰符的个数没有限制。如:可以通过*的个数区分指针的级别,**代表指向指针的指针,要想访问到最原始的对象,需要通过两次解引用,在内存中的表示就是一个新的地址空间存了上一个指针所在的地址。
3.存在指向指针的引用。如int *p; int *&r=p;
要想理解r的含义,最简单的办法就是从右向左阅读。在C++中里变量名越近的符号对变量的影响越大。
2.8:const的引用
引用所能进行的操作,受其绑定对象的限制。当其绑定的对象为常量时,则引用不能改变其对象的值,同时要求引用本身也必须是const的
引用的类型于其引用对象的类型必须保持一致的例外情况:
在初始化 常量引用 时,可以用任意表达式作为初始值,只要该表达式的结果能转化成引用的类型即可。尤其,允许绑定非常量的对象,字面值,甚至是一般表达式。(后两种情况会创建临时地址用于转化后的值/字面值/表达式的结果)
而对于 常量引用 引用非常量对象的行为虽然不算错误,但在在C++中被归为非法
2.9:指针和const(指向的对象是const的)
和常量引用一样,指向常量的指针不能用于改变其对象的值,同时想要存放常量对象的地址,只能用常量指针。
指针的类型和其指向对象的类型必须保持一致的例外情况(和常量引用类似):
允许常量指针指向非常量的对象,该情况下不能通过指针去改变对象的值(因为指针认为自己指向了常量),但是可以通过其他途径去该改变对象的值(因为对象不是常量)
2.10:const指针(指针本身是const的)
同其他基本的const对象一样,const指针也必须初始化,一旦初始化后便不能再改变
书写格式: 【对象类型 *const 变量名】把*放到const前说明指针是一个常量,同时不变的是指针而不是指针所指的对象
指针本身是常量只是指针的值不变(存放对象的地址),但是这不意味着不能通过解引用指针去改变所指向的对象的值
2.11:顶层const
哪些对象含有顶层const或/和底层const:
对于指针来说,指针本身和指针所指的对象是不是常量是两个独立的问题,进而引出顶层const(指针本身是const)和底层const(指针所指的对象是const)这两个概念。
拓展到一般情况,对于一般的数据类型,只含有顶层const,表示自己对象本身是否为const
而底层const则与指针和引用这样的复合类型有关。当引用所指对象是const,那么该引用含有底层const,但是引用不含顶层const,因为引用本身不是对象
因此只有指针对象可能同时拥有顶层和底层const,而对于引用最多只能拥有底层const,对于一般类型最多只能拥有顶层const
有关含底层/顶层const对象的拷贝操作:
在执行对象的拷贝操作时,顶层const可以忽略。
而底层const的限制不能被忽视,拷入和拷出对象必须具有相同的底层const;或者拷出对象无底层const,但是拷入对象有底层const。对此,我们可以先去掉顶层是否有const(底层const对底层的赋值不起任何的影响),只关注底层const,问题又回到了含const的对象的赋值问题上来。
2.12:使用别名时需要注意的问题
当别名声明一个复合类型(如指针)/常量时,对于一条声明语句不能直接直接将别名替换回原来的形式。一定要明确整个声明语句其基本类型到底是什么,若别名代表一个指针,则基本类型为指针。
如:typedef char* pstring; //别名代表一个指针
const pstring cstr=0; //const修饰这个别名(即指针),如果替换回char*就会发生错误
2.13:decltype和引用
如果decltype使用的是表达式,则其返回表达式结果对应的类型
若有int i=42,*p=&i,&r=i; 则decltype(r)得到引用类型,但decltype(r+0)得到一个int类型,而解引用操作得到引用类型(因为解引用指针可以得到指针所指的对象,而且还能给这个对象赋值,即解引用常出现在等号左侧)
同时decltype和auto另一个区别(还有一个是decltype保留顶层const)在于,decltype的结果类型与表达式形式密切相关。如果decltype使用的是一个不加括号的变量,则得到变量的类型。如果变量加上括号,就会被当作一个表达式(因为变量是一种可以作为赋值语句左值的特殊表达式),从而得到一个引用类型
原文地址:https://www.cnblogs.com/HDUjackyan/p/9811662.html