一篇吃透 C++ 核心基础:初始化、引用、指针、内联、重载、右值引用

大家好,本篇博客把 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 条对比(背会)

  1. 本质:指针存地址;引用是别名
  2. 空间:指针占内存;引用不占
  3. 空值:指针可 nullptr;引用不能为空
  4. 绑定:指针可改指向;引用不可重绑
  5. 解引用:指针需要 *;引用直接用
  6. 层级:指针有多级;引用只有一级
  7. sizeof:指针是地址长度;引用是变量大小
  8. ++/--:指针移动地址;引用修改变量值
  9. 参数检查:指针要判空;引用不用
    一句话:引用是更安全、更简洁的指针。

六、内联函数 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++ 特有的「名字粉碎」
作用:

  1. 让 C++ 编译器不粉碎函数名
  2. 编译后函数名还是 add
  3. 这样 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 &);

十、全篇速记总结

  1. 初始化优先 {},安全不隐式转换
  2. cout << a, b, c 只输出 a
  3. 引用 = 安全指针,底层 *const
  4. 指针权限只能收缩,不能放大
  5. inline 编译展开,比宏安全
  6. 缺省参数必须靠右连续
  7. 重载看参数,不看返回值
  8. 右值引用 && 绑定临时值
相关推荐
李日灐1 小时前
< 9 > Linux 进程:进程状态 + 进程切换 + 附带常用指令(jobs / fg / kill / ps)
linux·运维·服务器·后端·面试·进程状态
小明同学011 小时前
计算机网络编程---系统调用到并发模型
linux·c++·计算机网络
Royzst1 小时前
一、集合概述(前置基础)
开发语言·windows·python
Season4501 小时前
C/C++的类型转换
c语言·开发语言·c++
Titan20241 小时前
C++特殊类设计
c++·学习
cong_1 小时前
狐蒂云🦊跑路我的摸鱼岛没了!
前端·后端·github
明日清晨1 小时前
有符号与无符号数转换
c++
平安的平安1 小时前
Python大模型Function Calling实战:让AI拥有工具使用能力
开发语言·人工智能·python
xyq20241 小时前
Vue.js 实例
开发语言