前言
该系列是《C++Primer第五版》的笔记,包含本人认为值得记录和整理的主要的知识点,并不是全部内容,也不是具体的内容。
该系列文章的作用应该是作为复习或预习的参考,有哪些知识点忘记或想学,可以大致浏览下该文章,然后再去书中寻找详细解答。(本系列文章基本是按书本顺序罗列的知识点,便于大家去书中寻找)
所以看该文章前,需要有一定的C++基础,否则阅读起来可能有困难。
本文大致整理了第二章的知识点,属于C++比较基础的内容,有零星几个难点。
链接目录
- 第二章:变量与基本类型
- 第三章:字符串、向量和数组
- 第四章:表达式
- 第五章:语句
- 第六章:函数
- 第七章:类
- 第八章:IO库
- 第九章:顺序容器
- 第十章:泛型算法
- 第十一章:关联容器
- 第十二章:动态内存
- 第十三章:拷贝控制
- 第十四章:重载运算与类型转换
- 第十五章:面向对象程序设计
- 第十六章:模板与泛型编程
- 第十七章:标准库特殊设施
- 第十八章:用于大型程序的工具
- 第十九章:特殊工具与技术
基本内置类型
内置的数据类型具体的长度和机器及编译器相关,以下的是通常情况下的长度,仅供参考。
在算术运算中尽量不用char
,因为在不同机器中,char
可能被解释为带符号数或无符号数。
变量初始化
对于内置类型,在函数体外未显式初始化,默认初始化为0,在函数体内则不进行初始化,值是不确定的。
//例如int,a的值为0,b的值不确定
int a;
int main(){
int b;
return 0;
}
变量的声明和定义
C++为了支持分离式编译,声明和定义可以分开。
- 声明定义了变量的类型和名字
- 定义额外进行申请内存空间,初始化等操作
如果在多个文件中使用同一个变量,定义和声明需要分离开,定义只能出现在一个文件中,其他使用该变量的文件只能声明。
extern int i;//声明了i,但没定义
int j;//声明并定义了j,定义内容由默认初始化决定
引用
引用是对象的另一个名字,使用&
进行引用的定义。记住引用不是对象,没有实际地址,只是一个对象的别名。且有几个注意事项。
- 引用类型必须严格匹配
- 引用必须被初始化
- 不能定义引用的引用
int val = 1;
int &refI = i;//refI为i的引用
指针
指针与引用的不同点:
- 允许赋值和拷贝
- 可以在不同时刻指向不同的对象
- 无需在定义时就初始化
- 可以有指向另一个指针的指针
但也有几个注意事项:
- 不能定义指向引用的指针
- 大部分情况下(类的继承关系除外),指针类型和对象必须匹配
int i = 1;
int *p = &i;//p是指向i的指针
int **pp = &p;//pp是指向p的指针
指针的使用是非常容易出错的,访问无效指针会引发程序错误,但编译器并不负责检查。
我们可以通过解引用符*
访问指针指向的对象:cout << *p << endl;
空指针有三种形式:
0
NULL
nullptr
,C++11新引入的,推荐使用
const限定符
阻止对对象的修改,可以和其他关键字组合使用。
常量引用:用const
修饰的引用
- 一个常量对象的引用必须是常量引用
- 一个非常量对象,可以有常量引用,也可以有非常量引用
const int i = 1;
const int &r1 = i;//常量i的常量引用
int j = 1;
const int &r2 = j;//非常量j的常量引用
r2 = 2;//非法,无法修改常量引用
j = 2;//合法,对象本身非常量,可修改
指针和const
:和常量引用一样,指向常量对象的指针必须用const修饰,且不能通过该指针修改对象。
常量指针(const
指针):该指针本身是个常量,即指针的指向不可变,但仍可以通过该指针修改对象。
指针和const
速记:
const
在*
左侧,指针指向常量,所指对象不可变const
在*
右侧,常量指针,指针指向不可变
顶层const:表示指针本身是个常量,即指向不可变
底层const:表示指针所指对象是常量,即对象不可变
指针值在条件表达式中的使用:
- 如果指针值是0,则条件为
false
- 否则,为
true
constexpr和常量表达式
常量表达式:在编译过程中就能得到计算结果的表达式。
由于在复杂系统中,很难分辨一个表达式是不是常量表达式,所以C++11引入constexpr
变量,将常量表达式的检查交给编译器。
constexpr
变量:一定是常量,而且必须用常量表达式进行初始化。
//constexpr的用法
constexpr int bufSize = 32;
constexpr int limit = bufSize * 2;//用常量表达式进行初始化
constexpr int sz = size();//当size是一个constexpr函数时才正确
指针和constexpr
:如果指针和constexpr
组合,constexpr
只会对指针生效,即如果声明一个指针为constexpr
,则指针指向不可变。
类型别名
typedef
:定义类型别名
//number是int的别名,n是int*的别名
typedef int number, *n;
//C++11中等价的新方法
using number = int;
指针、常量和类型别名:难!!!容易产生令人困惑的结果
typedef int* pint;
int i = 1;
//此时const用于修饰指针,而不是对象,可以理解
//为const修饰pint,而pint是一个指针
const pint pi = &i;//pi是指向int的常量指针,指向无法更改,对象值可以更改
//此处可以理解为pint*是声明一个指向pint的指针
//而由于pi是一个常量,所以必须用常量指针
const pint* ps = π//ps是一个指针,所指对象是一个指向int的常量指针
*pi = 4;//可以通过常量指针修改对象,此时a为4
ps = &ps;//ps是一个指针,可以修改指向,但所指的对象无法修改指向
**ps = 1;//通过所指对象的所指对象修改b的值,此时b为1
auto类型说明符
auto
:C++11中引入的类型说明符,将类型判断交给编译器,必须进行初始化。在复杂的复合类型中非常好用。(通常是*
和const
等各种关键字的复杂组合,有时候难以判断是什么类型,只知道怎么使用这个类型,这时候就可以用auto)
另外,auto
通常会省略掉顶层const,但会保存底层const,如果希望推断出的auto
是顶层const,需要显式指出。例如:const auto &i = 1;
,是一个常量整数引用。
int i = 1;
auto j = i;//编译器通过i判断j的类型
//一个只能用auto的例子,可以暂时不用理解什么是lambda表达式
//我们无法准确知道f的类型,但知道如何使用它
auto f = []{return "hello";}
cout << f << endl;
decltype类型指示符
decltype
:C++11中引入的一种类型说明符,通过编译器分析表达式的类型,但并不会计算值。用途和auto
类似。
decltype
和引用:例如decltype(*p)
的结果是int&
而非int
(p是指向int
的指针)。
另外,decltype
对括号敏感,delctype((...))
一定是一个引用。
int i = 1;
decltype(i) j = 2;//通过i的类型来判断j的类型
头文件
本博客有一篇关于头文件的文章,介绍了基本的头文件保护符的使用示例。(文章链接)
头文件保护符:
#define
:把一个名字设定为于处理变量#ifdef
:当变量已定义时为真#ifndef
:当变量未定义时为真#endif
:当条件为真时,执行中间的语句直到#endif
未列入知识点
由于该部分的知识较为深入,当前阶段不易理解或使用,完整写出来篇幅较大。所以单独列出来,学有余力或兴趣的,可以自行去书中阅读。
void*
指针:可以用于存放任意类型的地址,但解读内存地址中的内容的方式未知。(726页有详细介绍)