C++ 核心基础概念梳理
C++ 兼容 C 语言,因此可以在 C++ 环境下编写 C 代码。 C++ 之父:本贾尼·斯特劳斯特卢普(Bjarne Stroustrup)
一、命名空间
在 C++ 中,我们常遇到标识符冲突的问题。比如 stdlib.h 中有 rand 函数,如果我们定义同名的变量,编译器可能会报错。
#include<stdio.h>
#include<stdlib.h>
int rand = 10;
int main() {
printf("%d\n", rand); // 全局变量 rand 与 stdlib.h 中的 rand 函数冲突,编译报错
}
但如果 rand 是局部变量,则不会冲突:
#include<stdio.h>
#include<stdlib.h>
int main() {
int rand = 10;
printf("%d\n", rand); // 局部变量优先,执行成功
}
1. 标识符查找规则
编译器查找标识符时,遵循从内向外的作用域查找原则。一旦在当前作用域找到匹配项,就不会继续向外层查找。
2. 命名空间的概念
为了解决同一作用域下的命名冲突,C++ 引入了命名空间(Namespace)。你可以把它理解为一个自定义的'域',用来存放标识符。
- 语法:
namespace 命名空间名 { // 自定义的标识符 } - 访问方式:使用
命名空间名::标识符。
示例:
#include<stdio.h>
#include<stdlib.h>
namespace mycode {
int rand = 10;
}
int main() {
printf("%d\n", mycode::rand); // 正常打印出 10
}
3. 命名空间的嵌套
当父域下仍有冲突时,可以使用嵌套命名空间来进一步隔离。
#include<stdio.h>
namespace code {
namespace codeA {
int a = 10;
}
namespace codeB {
int a = 20;
}
}
int main() {
printf("%d\n", code::codeA::a); // 打印 10
printf("%d\n", code::codeB::a); // 打印 20
}
4. 命名空间的使用技巧
除了显式指定,还有两种常用方式简化访问:
- 展开某个成员:只引入特定标识符。
using name::a; - 展开整个命名空间:一次性引入所有成员。
using namespace name;
注意:多个文件中可以定义同名命名空间,编译器会自动将它们合并。标准库都存放在
std命名空间中。
二、C++ 的输入输出
C++ 推荐使用 <iostream> 头文件进行控制台输入输出,它提供了 cin、cout 以及流操作符。
1. cin 和 cout
std::cin:控制台输入(Console Input)。std::cout:控制台输出(Console Output)。
由于它们位于 std 命名空间,使用前需加上 std:: 或使用 using namespace std;。
2. 流操作符
<<:流插入运算符,配合cout使用。>>:流提取运算符,配合cin使用。
C++ 能自动识别变量类型,无需像 C 语言那样手动指定占位符。
#include<iostream>
using namespace std;
int main() {
cout << "Hello World" << endl;
cout << "学习 C++ 很有趣" << endl << "加油!" << endl;
}
#include<iostream>
using namespace std;
int main() {
int a, b;
cout << "请输入两个整数:";
cin >> a >> b;
cout << "两个数之和为:" << a + b << endl;
}
3. endl
endl 表示换行并刷新缓冲区。
三、缺省参数
定义函数时,可以为参数指定默认值。调用时若不传该参数,则使用默认值;若传入,则覆盖默认值。
1. 全缺省与半缺省
- 全缺省:所有参数都有默认值。
- 半缺省:部分参数有默认值。关键规则:缺省值必须从右向左连续设置。调用时必须先传完没有缺省值的参数。
#include<iostream>
using namespace std;
void Print(int a, int b = 1, int c = 2) {
cout << a << "," << b << "," << c << endl;
}
int main() {
Print(0); // 打印 0,1,2
Print(6, 6); // 打印 6,6,2
Print(5, 5, 5); // 打印 5,5,5
}
提示:函数声明和定义分离时,缺省参数只能出现在声明部分。
四、函数重载
在同一作用域内,允许存在多个同名函数,但它们的参数列表必须不同(个数、类型或顺序不同)。
#include<iostream>
using namespace std;
// 参数个数不同
int Add(int a, int b, int c) { return a + b + c; }
int Add(int a, int b) { return a + b; }
// 参数类型不同
double Calc(int a, double b) { return a + b; }
double Calc(double a, int b) { return a - b; }
int main() {
cout << Add(1, 1, 1) << endl; // 调用三参数版本
cout << Add(1, 1) << endl; // 调用两参数版本
cout << Calc(2, 2.2) << endl; // 第一个参数是 int
cout << Calc(2.2, 2) << endl; // 第一个参数是 double
}
五、引用(Reference)
引用是给已有变量起的一个别名,直接操作原内存地址,不产生额外拷贝。
1. 基本语法
类型& 引用别名 = 引用对象;
2. 引用 vs 指针
| 特性 | 引用 | 指针 |
|---|---|---|
| 初始化 | 必须初始化 | 建议初始化 |
| 绑定后 | 不可更改指向 | 可重新赋值 |
| 空值 | 不存在空引用 | 可为 nullptr |
| 大小 | 取决于对象 | 取决于系统位数 |
3. 引用要求
- 初始化:定义时必须绑定有效对象。
- 别名唯一性:同一作用域下,引用名不能与原变量名相同。
- 多引用:一个变量可以有多个引用,修改任一引用都会影响原变量及其他引用。
#include<iostream>
using namespace std;
int main() {
int a = 2;
int& b = a;
int& c = a;
c++; // 修改 c,a 和 b 也会变
cout << a << "," << b << "," << c << endl;
}
六、const 引用
被 const 修饰的引用称为常量引用。它限制了通过引用修改变量的权限,常用于保护数据不被意外修改。
1. 权限控制
- 原变量可读可写,const 引用后变为只读。
- 原变量只读,const 引用后仍只读。
- 禁止权限放大:不能用普通引用绑定
const变量。
2. 修饰临时变量
普通引用不能绑定临时变量(如字面量),因为临时变量生命周期短且不安全。但 const 引用 可以延长临时变量的生命周期,直到引用销毁为止。
int main() {
const int& ra = 20; // 安全,延长了字面量 20 的生命周期
// int& rra = 20; // 错误,权限放大
}
七、宏与内联函数
1. 宏(Macro)
宏是预处理阶段的文本替换,分为有参和无参宏。
#define Add(a,b) ((a) + (b))
缺点:无类型检查,易受优先级影响,无法调试。
2. 内联函数(Inline Function)
inline 关键字建议编译器将函数体展开到调用处,避免栈帧开销,提高效率。
inline int Add(int a, int b) {
return a + b;
}
对比:
- 内联函数是真正的函数,支持类型检查和调试。
- 宏是文本替换,编译器无法拒绝宏替换。
八、nullptr
C++11 引入了 nullptr 关键字表示空指针。
为什么需要 nullptr?
在 C++ 中,NULL 通常定义为 0。在函数重载场景下,Print(NULL) 可能无法区分是指针还是整型,导致歧义。
#include<iostream>
using namespace std;
void Print(int* x) { cout << "int*" << endl; }
void Print(int x) { cout << "int" << endl; }
int main() {
Print(NULL); // 可能被解析为 int
Print(nullptr); // 明确解析为 int*
}
使用 nullptr 可以避免这种二义性,提升代码安全性。


