C++ primer 学习笔记(一)

1、 main函数的返回类型必须为int。

2、可寻址的最小内存块为字节,存储的基本单元为字。

3、带符号类型可以表示正数、负数或0,无符号类型则仅能表示大于等于0的值。

4、如果赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数
eg:unsigned char c = -1;
c=255;
取模运算时,对于负数,应该加上被除数的整数倍,使结果大于或等于0之后,再进行运算.
(-1)%256=(-1+256)%256=255%256=255;
当赋给带符号类型一个超出它表示范围的值时,结果是未定义的,此时程序可能继续工作,可能崩溃,也可能生成垃圾数据。

5、算数表达式中既有无符号数又有int值是,int值会转换成无符号数
正数转换为无符号数直接用原码表示,负数则用补码,即反码+1.结果等于这个负数加上无符号数的模。

6、以0开头的整数代表八进制数,以0x或0X开头的代表十六进制数.
浮点型字面值表现为一个小数或以科学计数法表示的指数,其中指数部分用E或e标识。默认浮点型字面值是一个double。

7、\X后紧跟一个或多个十六进制数字表示转义序列,\后紧跟一个,两个,三个八进制数字也表示转义序列。

8、true和false是布尔类型的字面值。nullptr是指针字面值。

9、对象是指一块能存储数据并具有某种类型的内存空间。

10、初始化与赋值的区别
初始化是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代。

11、默认初始化
如果是内置类型的变量未被显式初始化,它的值由定义的位置决定。定义于任何函数体之外(包括main函数)的变量被初始化为0,定义在函数体内部的内置类型将不被初始化,如果试图拷贝或以其他形式访问此类值将引发错误。
类的对象如果没有显式地初始化,其值由类决定。

12、分离式编译 允许将程序分割为若干个文件,每个文件可被独立编译。声明 使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个文字的声明。而定义负责创建与名字关联的实体。
如果想声明一个变量而非定义它,就在变量名前添加关键字extern,而且不要显式地初始化变量
eg:extern int i;声明i而非定义i
int j;声明并定义j
extern语句如果包含初始值就不再是声明,而变成定义了。
在函数体内部,如果试图初始化一个由extern关键字标记的变量,将引发错误,因为这意味着该变量被初始化两次。(extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义,此外extern也可用来进行链接指定。)
变量能且只能被定义一次,但是可以被多次声明。
声明:使得名字为程序所知,如果想使用该变量,则必须实现包含其声明。声明会确定变量的名字和类型。
定义:创建于名字关联的实体。定义会申请存储空间,可能会赋予初始值。

13、字母+数字+下划线(必须以字母或者下划线开头)
C++中关于变量命名的规范:
(1):能体现变量的实际意义
(2):变量名一般采用小写字母
(3):用户自定义变量名可以以大写字母开头
(4):多个单词定义的变量名应有区分Student_loan 而不是 Studentloan.

14、名字的有效区域始于名字的声明语句,以声明语句所在的作用域末端为结束。
作用域能彼此包含,被包含(或者说被嵌套)的作用域成为内层作用域,包含着别的作用域的作用域成为外层作用域

15、因为const对象一旦创建后其值就不能再改变,所以const对象必须初始化。
默认情况下,const对象被设定为仅在文件内有效。当多个文件中出现了同名的const变量时,其实等同于在不同文件中分别定义了独立的变量。
如果想只在一个文件中定义const,而在其他多个文件中声明并使用它,则对于const变量不管是声明还是定义都添加extern关键字。

16、可以把引用绑定到const对象上,称之为对常量的引用
对常量的引用不能被用作修改它所绑定的对象。
eg:const int ci=1024;
const int &r1 = ci; 正确,引用及其对应的对象都是常量
r1 =42; 错误,r1是对常量的引用
int &r2 = ci; 错误:试图让一个非常量引用指向一个常量对象。

17、通过将声明符写成&d的形式来定义引用类型,其中d是声明的变量名:
eg:int ival =1024;
int &refVal = ival; //refVal指向ival(是ival的另一个名字)
因为无法令引用重新绑定到另一个对象,因此引用必须初始化。
引用即别名
为引用赋值,实际上是把值赋给了与引用绑定的对象
获取引用的值,实际上是获取了与引用绑定的对象的值
以引用作为初始值,实际上是以与引用绑定的对象作为初始值
因为引用本身不是对象,所以不能定义引用的引用。
引用类型的初始值必须是一个对象。
在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可;
常量引用仅对引用可参与的操作做出了限定,对于引用的对象本身是不是一个常量未作限定,因为对象也可能是个非常量,所以允许通过其他途径改变它的值
eg:int i =42;
int &r1 = i;
const int &r2 = i;
r1 = 0; /r1并非常量,i的值修改为0
r2 = 0; /r2是一个常量引用,错误

18、指向常量的指针 不能用于改变其所指对象的值,要想存放常量对象的地址,只能使用指向常量的指针。
eg:
const double pi =3.14;
double *ptr = π 错误,ptr是一个普通指针
const double *cptr = π 正确
*cptr = 42; 错误,不能给*cptr赋值

注意:允许令一个指向常量的指针指向一个非常量对象,指向常量的指针没有规定其所指的对象必须是一个常量,所谓指向常量的指针仅仅要求不能通过该指针改变对象的值,而没有规定那个对象的值不能通过其他途径改变。

19、指针是对象而引用不是,允许把指针本身定为常量。
常量指针必须被初始化,而且一旦初始化完成,则它的值(也就是存放在指针中的那个地址)就不能再改变了;
把*放在const关键字之前用以说明指针是一个常量,即不变的是指针本身的值而非指向的那个值。
*如果const位于的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;
如果const位于的右侧,const就是修饰指针本身,即指针本身是常量。*
eg:
int errNumb = 0;
int *const curErr = &errNumb; //curErr将一直指向errNumb
const double pi =3.14159;
const double *const pip = π //pip是一个指向常量对象的常量指针;
从右向左阅读

20、顶层const表示指针本身是个常量,也可表示任意的对象是常量
底层const表示指针指向的对象是一个常量
eg:
int i = 0;
int *const p1 = &i; 不能改变p1的值,这是一个顶层cosnt
const int ci = 42; 不能改变ci的值,这是一个顶层const
const int *p2 = &ci; 允许改变p2的值,这是一个底层cosnt
const int *cosnt p3 = p2; 靠右的const是顶层const,靠左的是底层const
const int &r = ci; 用于声明引用的const都是底层const
当执行对象的拷贝操作时,拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的类型能够转换,一般来说,非常量可以转换成常量,反之则不行。

21、常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。
字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。
一个对象是不是常量表达式由它的数据类型和初始值共同决定。
C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。
声明为constexpr的变量一定是一个常量,而且必须用常量表达式来初始化。
尽管指针和引用都能定义成constexpr,但他们的初始值却受到严格限制。一个constexpr指针的初始值必须是nullptr或者是0,或者是存储于某个固定地址中的对象。
函数体内定义的变量一般来说并非存放在固定地址中,因此constexpr指针不能指向这样的变量。相反的,定义于所有函数体之外的对象其地址固定不变,能用来初始化constexpr指针。
在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指的对象无关:
eg: const int *p = nullptr; p是一个指向整型常量的指针
constexpr int *q = nullptr; q是一个指向整型的常量指针
关键在于constexpr把它所定义的对象置为了顶层const

22、static的作用
(1)隐藏
当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性
(2)默认初始化为0,包括未初始化的全局静态变量和局部静态变量。
(3)保持局部变量内容的持久。生存期为整个源程序,但作用域仍与局部变量相同,退出该函数后,尽管该变量还继续存在,但不能使用它。

23、static数据成员必须在类定义体的外部定义
例外“基本整型const static数据成员可以在类的定义体中进行初始化,但仍必须在类的定义体之外进行定义,只不过定义时,不再需要初始化。

24、静态成员函数由于不与任何的对象相关联,因此它不具有this指针。因而它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数。
因为static成员不是任何对象的组成部分,所以static成员函数不能被声明为const
最后,static成员函数也不能被声明为虚函数、volatile

25、静态成员函数总结
(1)静态成员之间可以互相访问,包括静态成员函数访问静态成员和访问静态成员函数。静态成员函数不能访问非静态成员函数和非静态数据成员,非静态成员函数可以任意的访问静态成员函数和静态数据成员
(2)由于没有this指针的额外开销,因此静态成员函数与类的非静态成员函数相比速度上会有少许的增长。

26、cosnt与#define的优点:
(1)const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误;
(2)使用常量可能比使用#define导致产生更小的目标代码,这是因为预处理器”盲目地将宏名称BUFSIZE替换为其代替的值“100”可能导致目标代码出现多份100的备份,但常量就不会出现这种情况。
(3)同时const还可以执行常量折叠(常量折叠是在编译时间简单化常量表达的一个过程,简单来说就是将常量表达式计算求值,并用求得的值来替换表达式,放入常量表),也就是说,编译器在编译时可以通过必要的计算把一个复杂的常量表达式缩减成简单的。

27、类型别名–typedef
eg:typedef double wages; wages是double的同义词
typedef wages base, p; base是double的同义词, p是double 的同义词
或使用别名声明来定义类型的别名:
using SI = Sales_item; SI是Sales_item的同义词
这种方法用关键字using作为别名声明的开始,其后紧跟别名和等号,其作用是把等号左侧的名字规定成等号右侧类型的别名。

28、auto让编译器通过初始值来推算变量的类型,auto定义的变量必须有初始值;auto语句中所有变量的初始基本数据类型必须一样。
auto一般会忽略掉顶层const,同时底层const则会保留下来。如果希望推断出的auto类型是一个顶层const,需要明确指出:
const auto f = ci; //ci的推演类型是int,f是const int。

29、decltype:选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。
eg:decltype(f()) sum = x; sum的类型就是函数f的返回类型。
如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型。
decltype的表达式如果是加上了括号的变量,结果将是引用。
加双层括号永远是应用,单层括号只有当变量时引用时才是引用。

30、赋值的表达式语句本身是一种引用

31、头文件通常包含那些只能被定义一次的实体,如类、const和constexpr变量。

32、#define指令把一个名字设定为预处理变量
#ifdef当且仅当变量已定义时为真
#ifndef当且仅当变量未定义时为真
一旦检查结果为真,则执行后续操作直至遇到#endif指令为止。

猜你喜欢

转载自blog.csdn.net/qq_38224589/article/details/81458678
今日推荐