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



评论前必须登录!
注册