大家好,本篇博客把 C++ 入门最常考、最易错、最核心的知识点一次性汇总讲透。内容涵盖变量初始化、引用与指针、const 指针、输入输出、内联函数、缺省参数、函数重载、名字粉碎、右值引用,全部是面试与日常开发必背内容,学完直接能用。
一、C++ 变量初始化:三种方式与安全规则
C++ 提供三种初始化写法,安全性与类型检查完全不同。
1. 三种初始化语法
- C 传统赋值
cpp
int a = 10;
- 小括号初始化
cpp
int b(20);
int c = (50);
- 大括号初始化(列表初始化,C++11 推荐)
cpp
int d{30};
int e = {30};
int f{1, }; // 末尾逗号允许
2. 关键语法规则
- 大括号 {} 末尾允许多余逗号
- 小括号 () 末尾不允许多余逗号
- int h(5, ); 报错
- 注意:int h();这里并不是将h初始化为0,这是一个函数声明
3. 类型安全(最重要)
- = / ():不做严格检查,隐式转换
cpp
int x(2.5); // OK,自动截断(不安全)
int y = 3.3; // OK,自动截断(不安全)
- {}:严格类型检查,禁止窄化转换
cpp
int z{3.3}; // ERROR!直接报错,杜绝精度丢失
4. 最佳实践
一律使用 {} 大括号初始化:统一语法、严格检查、更安全。
二、C++ 输入输出 cin / cout 核心用法
C++ 的 cin/cout 自动识别类型 (只能识别基本数据类型),不用写 %d/%f这样的占位符。
1. 标准输出 cout
cpp
cout << "a=" << a << " b=" << b << endl;
- <<:插入运算符
- endl:换行并刷新缓冲区
- 自动识别类型:int、float、char 都能直接输出
2. 标准输入 cin
cpp
cin >> a >> b >> c;
- >>:提取运算符
- 以空格、Tab、回车分隔
3. 超级易错点:逗号陷阱
cpp
//逗号运算符 , 优先级非常非常低,比 << 还低
cout << a , b, c; // 只输出 a!后面是逗号表达式,被忽略
cout << (a, b, c); // 输出 c!逗号表达式取最后一个值
正确连续输出: cout << a << b << c;
三、引用 & :语法、本质、与指针的区别
引用是 C++ 最优雅的"地址传递",底层是指针,语法像变量 。编译器将引用转化成 数据类型 * const
1. 引用基本语法
cpp
int a = 10;
int& ar = a; // ar 是 a 的别名
ar = 20; // 等价 a = 20
- 引用必须初始化,不能为空
- 引用不能重新绑定其他变量
2. 引用做函数参数(替代指针)
cpp
void swap(int& a, int& b) {
int t = a; a = b; b = t;
}
// 调用
swap(x, y); // 不用取地址 &
3. const 引用(万能引用)
cpp
void func(const int& r);
可以接收:
- 普通变量
- const 变量
- 常量/右值(100、表达式结果)
4. 引用底层本质
编译器把引用处理为: 数据类型 * const
cpp
int& ar = a; // 等价于 int* const ar = &a;
5. 高级引用
- 指针的引用:指针类型 & 引用名 = 变量名
cpp
int* p = &a;
int*& pr = p;
- 数组的引用:数组类型 (&引用名)[长度] = 数组名;
cpp
int arr[10];
//类似于数组指针的写法
//数组指针:数组类型(*指针名)[数组长度] = 数组名;
int (&arr_ref)[10] = arr;
四、指针 & const 组合:4 种写法必背
const 与指针的位置决定权限,C++ 只允许权限收缩,不允许放大。
cpp
int x = 10;
// 1. 底层 const:指向的内容不能改(常量指针)
const int* p1 = &x;
// 2. 顶层 const:指针本身不能改(指针常量)
int* const p2 = &x;
// 3. 完全 const
const int* const p3 = &x;
// 4. 普通指针
int* p4 = &x;
权限规则
- int* → const int* ✅ 收缩
- const int* → int* ❌ 放大(报错)
- 【注意】 后const 不影响 能力放大与收缩
cpp
int x = 5;
//前const
const int* xp1 = &x; // int * -> const int *
//后const
int* const xp2 = &x; // int * -> int * const
//int* const p = xp1; // const int * 放大 int *: 不合法
const int* q = xp2; // int* 缩小 const int *: 合法
五、引用 vs 指针:面试 9 条对比(背会)
- 本质:指针存地址;引用是别名
- 空间:指针占内存;引用不占
- 空值:指针可 nullptr;引用不能为空
- 绑定:指针可改指向;引用不可重绑
- 解引用:指针需要 *;引用直接用
- 层级:指针有多级;引用只有一级
- sizeof:指针是地址长度;引用是变量大小
- ++/--:指针移动地址;引用修改变量值
- 参数检查:指针要判空;引用不用
一句话:引用是更安全、更简洁的指针。
六、内联函数 inline:以空间换时间
1. 普通函数调用开销
- 建立栈帧
- 参数入栈
- 执行
- 返回、销毁栈帧
2. 内联函数特性
- 只是建议编译器,生成为内联函数
cpp
inline int add(int a, int b) { return a + b; }
- 编译时在调用处展开 ,无调用开销
- 以空间换时间
- 适合:简单计算、避免循环/多分支
- inline 只是建议,编译器有权拒绝
3. 内联 vs 宏(面试必问)
- 宏 :预处理文本替换,无类型/语法检查
- inline :编译期展开,有类型检查、安全可靠
七、缺省参数:函数默认值
规则
- 给形参赋默认值,调用时可省略
- 从右往左连续默认,中间不能断
- 形参表上,某一个参数存在默认值时,其后所有参数都应该有默认值。
cpp
int func1(int a, int b=1, int c=2); // OK
int func2(int a=1, int b, int c=2); // ERROR
int main()
{
func1(10); //后面的参数省略不传,默认用默认参数
}
八、函数重载:同名函数多版本
函数重载 使得相同名称的函数存在多个, 称之为函数集合
重载条件
- 函数名相同
- 参数不同(个数/类型)
- 与返回值无关
cpp
int add(int a, int b);
float add(float a, float b);
int add(int a, int b, int c);
如何匹配重载的函数?
调用函数时,依据个数、数据类型 匹配重载函数
cpp
add(1,2); //int add(int a, int b);
add(1.2,2.3); //float add(float a, float b);
add(1,2,3); //int add(int a, int b, int c);
C++ 为什么支持重载?
名字粉碎机制
函数名在编译时,使用特定的格式重新命名。保证底层唯一。
格式示例:(?函数名@@{调用约定标记}{返回类型标记}{参数表标记}@Z)
调用约定: __cdecl 默认, __stdcall, __fastcall, __thiscall
__cdecl YA 标记, 参数的入栈顺序: 先右后左
__stdcall YG 标记, 同上
__fastcall YI 标记, 将前2个参数压入ECX/EDX寄存储器, 其他按上面的方式入栈
- 包含:调用约定、返回值、参数类型
关闭名字粉碎(兼容 C):
cpp
extern "C" {
int add(int a, int b);
}
告诉 C++ 编译器:按照 C 语言的规则编译这段代码,不要做 C++ 特有的「名字粉碎」
作用:
- 让 C++ 编译器不粉碎函数名
- 编译后函数名还是 add
- 这样 C 代码和 C++ 代码就能互相调用
场景 1:C++ 调用 C 写的库
C 写的函数 → C++ 想调用必须加 extern "C",否则找不到函数
场景 2:C 调用 C++ 写的函数
C++ 写的函数要给 C 用必须包起来,否则 C 找不到名字
九、右值引用 && :移动语义基础
1. 左值 vs 右值
- 左值:有名、可取地址(变量、引用)
- 右值:无名、不能取地址(常量、表达式临时值)
2. 右值引用语法
格式:数据类型 && 引用名 = 右值;
cpp
int&& r = 100; // 绑定右值
int a = 10; // a 左值,10 右值
int b= a > 10 ? 10 : 5; // 表达式是右值
int &&r1= (a > b ? a : b); // 表达式的结果是左值
int &&r2= a > b ? a : b - 5; // 表达式中包含右值时,则为右值
- **右值引用本身是左值,**也有自己的存储空间(可以被修改、取地址)
- 用于:移动构造、移动赋值、完美转发
3. 重载匹配优先级
cpp
//这里值全都为int类型
func(左值); // 最佳匹配重载函数: func(int &); func(const int &);
func(const 左值); // 最佳匹配重载函数: func(const int &);
func(常量/右值); // 最佳匹配重载函数: func(int &&); func(const int &);
十、全篇速记总结
- 初始化优先 {},安全不隐式转换
- cout << a, b, c 只输出 a
- 引用 = 安全指针,底层 *const
- 指针权限只能收缩,不能放大
- inline 编译展开,比宏安全
- 缺省参数必须靠右连续
- 重载看参数,不看返回值
- 右值引用 && 绑定临时值