C++ 入门基础复习:从 C 到 C++ 的关键变化一次搞懂
本篇根据你提供的
01.C++入门基础.pdf整理
目标不是重新学习,而是帮助你把以前学过的知识快速重新串起来
按照你的要求,计算机历史相关内容不整理,并且全文去掉中文句号。
文章目录
- C++ 入门基础复习:从 C 到 C++ 的关键变化一次搞懂
- 一、C++ 和 C 的关系
- 二、命名空间 namespace
- 为什么需要命名空间?
- 三、namespace 的基本使用
- 四、std 命名空间
- 五、using namespace std
- 六、C++ 输入输出
- cout
- cin
- 七、cin 和 scanf 的区别
- 八、C++ 输入输出效率
- 九、缺省参数
- 十、缺省参数的本质
- 十一、全缺省参数
- 十二、半缺省参数
- 十三、缺省参数的重要规则
- 规则一
- 规则二
- 十四、函数重载
- 十五、什么条件能够构成函数重载
- 十六、返回值不同不能构成函数重载
- 十七、引用
- 十八、引用的特点
- 十九、引用必须初始化
- 二十、引用不是重新创建一个变量
- 二十一、引用和指针的关系
- 二十二、引用作为函数参数
- 二十三、引用为什么适合做参数
- 二十四、const 引用
- 二十五、const 引用可以引用普通变量
- 二十六、const 引用可以引用临时对象
- 二十七、为什么函数参数经常使用 const 引用
- 第一
- 第二
- 二十八、临时对象
- 二十九、这一篇需要重点回忆什么
- 三十、复习时最容易混淆的几个地方
- 1 赋值和引用不要混淆
- 2 指针和引用不要混淆
- 3 const int* 和 const int& 不要混淆
- 三十一、这一篇的最终记忆框架
一、C++ 和 C 的关系
学习 C++ 时,首先要明确一个概念
C++ 并不是完全推翻 C 重新设计的一门语言
它是在 C 语言基础上不断扩展形成的语言
所以你之前学过的很多 C 语言知识,在 C++ 中依然存在
例如
inta=10;doubleb=3.14;charc='a';if(a>0){printf("hello\n");}for(inti=0;i<10;++i){printf("%d\n",i);}这些基础语法依然可以使用
C++ 真正新增和强化的部分,主要体现在
命名空间 输入输出流 函数重载 缺省参数 引用 面向对象 类和对象 封装 继承 多态 模板 STL因此学习 C++ 的时候,不应该把它理解成
C 语言完全没用了
而应该理解成
C++ 在 C 语言基础上增加了大量更强大的语言机制
二、命名空间 namespace
这是 C++ 入门阶段非常重要的知识
为什么需要命名空间?
假设我们写了两个函数
voidTest(){printf("Test1\n");}voidTest(){printf("Test2\n");}这样直接编译会产生问题
因为同一个作用域中不能存在两个完全相同的函数
现实开发中,不同的人编写不同模块时,很容易出现名字冲突
例如
张三的代码intrand;李四的代码
intrand;如果最后把两个模块放到一起,就可能产生命名冲突
命名空间就是用来解决这个问题的
三、namespace 的基本使用
可以把不同的代码放到不同的命名空间里面
namespaceZhangSan{inta=10;}namespaceLiSi{inta=20;}此时虽然两个变量都叫
a但是它们属于不同的命名空间
使用的时候可以通过
ZhangSan::a和
LiSi::a进行区分
这里的
::叫做作用域解析运算符
四、std 命名空间
C++ 标准库中的大量内容都放在
std命名空间里面
例如
std::cout std::cin std::endl std::string std::vector所以最标准的写法是
#include<iostream>intmain(){std::cout<<"hello"<<std::endl;return0;}这里
std::就表示从std命名空间中寻找对应的内容
五、using namespace std
为了避免每次都写
std::可以使用
usingnamespacestd;例如
#include<iostream>usingnamespacestd;intmain(){cout<<"hello"<<endl;return0;}这样就可以直接使用
cout cin endl而不用写
std::cout std::cin std::endl日常练习中可以使用
using namespace std,实际项目开发中不建议直接使用它
原因主要是
如果命名空间中的名字非常多,全部展开以后可能再次造成命名冲突
因此实际项目中更常见
std::cout std::vector<int>std::string这种写法
六、C++ 输入输出
C++ 中最常见的输入输出方式是
cin cout需要包含
#include<iostream>cout
例如
inta=10;doubleb=3.14;charc='a';cout<<a<<endl;cout<<b<<endl;cout<<c<<endl;也可以连续输出
cout<<a<<" "<<b<<" "<<c<<endl;这里
<<叫做流插入运算符
可以简单理解为
把右边的数据交给 cout 输出cin
C++ 输入使用
cin>>变量;例如
inta;doubleb;charc;cin>>a;cin>>b;cin>>c;也可以连续输入
cin>>a>>b>>c;这里
>>叫做流提取运算符
可以简单理解成
从 cin 中提取数据七、cin 和 scanf 的区别
C 语言中通常写
inta;doubleb;scanf("%d%lf",&a,&b);C++ 中可以写
inta;doubleb;cin>>a>>b;最大的区别之一就是
C++ 的流输入能够根据变量类型自动处理
不需要自己写
%d%lf%c这样的格式控制符
C++ 输入输出本质上涉及函数重载以及后续面向对象相关知识,所以这里先理解使用方式即可
八、C++ 输入输出效率
如果只是普通练习
cin cout直接使用即可
在大量输入输出的场景中,可以使用
ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);例如
#include<iostream>usingnamespacestd;intmain(){ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);return0;}这主要用于提高 C++ IO 的效率
在 IO 需求比较高的地方,例如部分大量输入的竞赛题中,可以加入这些代码
九、缺省参数
缺省参数是 C++ 对函数参数进行扩展的重要特性
例如
voidFunc(inta=10){cout<<a<<endl;}调用
Func();相当于使用
Func(10);也可以主动传参数
Func(20);此时使用的就是
20而不是默认值10
十、缺省参数的本质
例如
voidTest(inta=10){cout<<a<<endl;}调用
Test();因为没有给a提供实参,所以使用默认值
10调用
Test(100);因为提供了实参,所以使用
100所以可以记成
没有传参数 → 使用默认值 传了参数 → 使用传入的值十一、全缺省参数
例如
voidTest(inta=10,intb=20,intc=30){cout<<a<<" ";cout<<b<<" ";cout<<c<<endl;}那么下面几种调用都可以
Test();相当于
Test(10,20,30);Test(100);相当于
Test(100,20,30);Test(100,200);相当于
Test(100,200,30);Test(100,200,300);相当于
Test(100,200,300);十二、半缺省参数
例如
voidTest(inta,intb=20,intc=30){}这里
a没有默认值
而
b c有默认值
所以调用
Test(10);是合法的
相当于
Test(10,20,30);但是
Test();不合法
因为a没有默认值
十三、缺省参数的重要规则
需要重点记住
规则一
缺省参数一般从右往左连续提供
正确
voidTest(inta,intb=10,intc=20);不应该写成
voidTest(inta=10,intb,intc=20);因为中间出现了没有默认值的参数
规则二
函数声明和定义中不能重复给默认值
例如
voidTest(inta=10);定义时
voidTest(inta){}这样即可
不要写成
voidTest(inta=10){}十四、函数重载
函数重载也是 C++ 非常重要的特性
例如
intAdd(inta,intb){returna+b;}doubleAdd(doublea,doubleb){returna+b;}虽然两个函数名字都叫
Add但是参数不同
因此可以同时存在
调用
Add(1,2);会匹配
intAdd(int,int)调用
Add(1.1,2.2);会匹配
doubleAdd(double,double)十五、什么条件能够构成函数重载
函数重载要求
函数名相同,参数列表不同
参数列表不同可以表现为
参数个数不同 参数类型不同 参数顺序不同例如
voidTest(inta);voidTest(inta,intb);可以重载
voidTest(inta);voidTest(doublea);也可以重载
voidTest(inta,doubleb);voidTest(doublea,intb);也可以重载
十六、返回值不同不能构成函数重载
下面这种情况不行
intTest(){return1;}doubleTest(){return1.0;}因为两个函数
Test()参数列表完全一样
仅仅返回值不同
不能构成重载
所以记住
不能只靠返回值区分函数重载
十七、引用
引用是 C++ 非常核心的一个知识点
基本语法
inta=10;int&ra=a;这里
ra是
a的别名
可以理解成
a 是一个变量 ra 是 a 的另一个名字十八、引用的特点
例如
inta=10;int&ra=a;ra=20;此时
cout<<a<<endl;结果是
20因为
ra和
a实际上指向同一个对象
十九、引用必须初始化
例如
inta=10;int&ra=a;正确
但是不能写
int&ra;引用在定义的时候必须初始化
也就是说必须明确
ra 是谁的别名二十、引用不是重新创建一个变量
例如
inta=10;int&ra=a;不要把它理解成
又创建了一个 int 类型变量 ra更准确的理解是
ra 是 a 的别名引用是一个变量的取别名,而指针是存储一个变量地址
二十一、引用和指针的关系
这部分非常重要
可以先从概念上区分
| 对比 | 指针 | 引用 |
|---|---|---|
| 本质 | 存储地址 | 变量别名 |
| 是否需要初始化 | 语法上不强制 | 必须初始化 |
| 是否可以为空 | 可以有nullptr | 通常不应该理解成空引用 |
| 使用方式 | *p | 直接使用 |
| 是否可以修改指向 | 可以 | 初始化后不能改绑 |
| 是否开空间 | 指针本身需要空间 | 语言层面不把引用理解为独立对象 |
指针和引用虽然存在功能重叠,但二者并不能完全互相替代
二十二、引用作为函数参数
这是引用最常见的用途之一
例如交换两个变量
C 语言中通常使用指针
voidSwap(int*px,int*py){inttmp=*px;*px=*py;*py=tmp;}调用
inta=10;intb=20;Swap(&a,&b);C++ 可以使用引用
voidSwap(int&x,int&y){inttmp=x;x=y;y=tmp;}调用
Swap(a,b);这样就不需要显式写
&*二十三、引用为什么适合做参数
假设
voidFunc(intx){}传参的时候会产生一份值拷贝
而
voidFunc(int&x){}这里x是原变量的别名
因此可以直接操作原变量
例如
voidAdd(int&x){x++;}inta=10;Add(a);执行之后
a==11二十四、const 引用
这一部分是引用中非常容易考的知识
例如
constinta=10;此时不能用普通引用
int&ra=a;因为这样相当于把一个
不能修改的对象变成了
可以通过 ra 修改的对象这属于权限放大
因此应该写
constint&ra=a;二十五、const 引用可以引用普通变量
例如
inta=10;constint&ra=a;这是可以的
但是此时不能通过ra修改a
// ra++;不允许
但是
a++;依然可以
因为真正的变量a本身不是 const
只是ra这个访问入口具有只读权限
二十六、const 引用可以引用临时对象
例如
constint&ra=10;这是合法的
还可以
inta=10;constint&rb=a*3;这里
a*3产生的是一个临时结果
C++ 可以让const引用绑定到这个临时对象
二十七、为什么函数参数经常使用 const 引用
例如
voidPrint(conststring&s){cout<<s<<endl;}这样做同时解决了两个问题
第一
避免大对象进行拷贝
第二
保证函数不会修改传入对象
所以以后看到
constT&经常可以理解成
不想拷贝 + 不允许修改这是 C++ 中非常常见的一种函数参数写法
二十八、临时对象
什么叫临时对象
例如
inta=10;a+3;表达式
a+3会产生一个计算结果
这个结果并没有一个我们明确命名的变量
C++ 会在需要的时候创建一个临时对象保存这个结果
例如
constint&rb=a*3;rb可以引用这个临时对象
二十九、这一篇需要重点回忆什么
如果你以前已经学过这些内容,现在复习的时候不需要重新死记全部细节
建议重点重新建立下面这条知识链
C++ ↓ namespace ↓ std 命名空间 ↓ cin / cout ↓ 缺省参数 ↓ 函数重载 ↓ 引用 ↓ const 引用 ↓ 临时对象 ↓ 指针和引用的区别其中真正需要重点掌握的是
namespace 为什么存在 :: using namespace std 的作用 cin / cout 的基本使用 缺省参数规则 函数重载的判断条件 为什么返回值不同不能构成重载 引用是什么 引用为什么必须初始化 引用和指针有什么区别 const 引用为什么可以绑定临时对象三十、复习时最容易混淆的几个地方
1 赋值和引用不要混淆
inta=10;intb=a;这里是拷贝
a = 10 b = 10两个变量是独立的
而
inta=10;int&b=a;这里是引用
b 是 a 的别名2 指针和引用不要混淆
inta=10;int*p=&a;int&r=a;使用指针
*p=20;使用引用
r=20;最终都会修改a
但二者的语言概念完全不同
3 const int* 和 const int& 不要混淆
指针
constint*p;重点是
不能通过 p 修改它指向的对象引用
constint&r=a;重点是
不能通过 r 修改对象三十一、这一篇的最终记忆框架
以后重新看到 C++ 入门基础的时候,可以直接在脑子里回忆成下面这个框架
C++ 基础 │ ├── 命名空间 │ ├── namespace │ ├── 作用域解析运算符 :: │ ├── std │ └── using namespace std │ ├── 输入输出 │ ├── cin │ ├── cout │ ├── endl │ └── IO 效率 │ ├── 函数增强 │ ├── 缺省参数 │ └── 函数重载 │ └── 引用 ├── 基本概念 ├── 引用初始化 ├── 引用作为参数 ├── const 引用 ├── 临时对象 └── 指针和引用的区别这一部分复习完之后,真正需要做到的不是能够背出定义,而是看到代码能够马上判断:
inta=10;int&b=a;知道b是a的别名
看到
constint&b=a;知道b只能读不能通过它修改a
看到
voidTest(inta=10);知道这是缺省参数
看到
voidTest(int);voidTest(double);知道这是函数重载
看到
std::cout知道cout属于std命名空间
看到
constint&r=a+10;知道这里涉及临时对象和常引用绑定
这些才是复习阶段最重要的内容