跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

C++ 基础概念

C++ 的基础概念,涵盖命名空间及其嵌套解决标识符冲突的方法,C++ 输入输出流 iostream 及 cin/cout 的使用,缺省参数的定义与规则,函数重载的条件与示例,引用的概念、语法、要求及与指针的区别,const 引用对临时变量和常量的修饰,宏的定义与内联函数的对比,以及 C++11 中 nullptr 关键字的引入原因。文章通过代码示例详细讲解了各知识点的具体用法和注意事项。

未来可期发布于 2026/3/30更新于 2026/7/2140 浏览
C++ 基础概念

C++ 基础概念

C++是兼容C的,所以我们可以在C++环境下写C语言。

C++之父:本贾尼・斯特劳斯特卢普。

一、命名空间

#include <stdio.h>
#include <stdlib.h>
int main() {
    int rand = 10;
    printf("%d\n", rand); // 代码可以正确执行
}
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main() {
    printf("%d\n", rand); // 会编译报错
}

思考:stdlib.h中存在 rand 这个函数,那么我们却自定义了 rand 这个变量。当 rand 是局部变量时,代码可以成功执行,当 rand 是全局变量时却会引起编译报错,这是什么原因呢?

下面我们需要了解 C++ 的标识符查找规则和引起标识符命名冲突的本质原因。

(1)C++标识符查找规则

标识符:变量、函数、类、常量、命名空间。

编译器查找标识符时,会从当前最内层的作用域开始查找;如果找到了,就不会再去外层作用域查找。

(2)引起标识符命名冲突的本质原因

同一作用域下不能存在同名的标识符。

那么用怎么样才能避免编译报错呢?

这里就引入了命名空间的概念。

(3)命名空间

①概念

命名空间就是我自己造了一个域,用来存放标识符。用来解决同一个域下命名冲突的问题。

用(命名空间名::标识符)来访问我域里的标识符。

②语法

语法:

namespace 命名空间名 {
    // 你自定义的标识符
}
③解决标识符冲突问题
#include <stdio.h>
#include <stdlib.h>
namespace mycode{
    int rand = 10;
}
int main() {
    printf("%d\n", mycode::rand); // 正常打印出 10
}

那么在同一个命名空间下,标识符一样该怎么处理,这里我们就需要了解命名空间的嵌套。

(4)命名空间的嵌套

①概念

在父域里辟多个子域。用来解决父域中标识符冲突问题。用(父域命名空间名::子域 1::标识符)来访问我域里的标识符。

②语法
namespace 外层命名空间名 {
    namespace 内层命名空间名 1 {
        // 你自定义的标识符
    }
    namespace 内层命名空间名 2 {
        // 你自定义的标识符
    }
    //......
}
③示例
#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
}

(5)命名空间的使用

①指定命名空间访问

就是我们前面用的 ::

②展开某个成员访问

就是访问命名空间里的某个成员。

语法:

using 命名空间名::成员;

示例:

#include <stdio.h>
namespace name {
    int a = 3;
    int b = 6;
}
int main() {
    using name::a; // 展开某个成员
    printf("%d\n", a);
}
③展开命名空间的全部成员

语法:

using namespace 命名空间名;

示例:

#include <stdio.h>
namespace name {
    int a = 3;
    int b = 6;
}
int main() {
    using namespace name; // 展开全部成员
    printf("%d\n", a);
    printf("%d\n", b);
}

(6)补充

在多个文件使用命名空间时

C++ 不允许同一个作用域下有两个同名的类或变量,但允许同一个命名空间被写在不同的文件、不同的位置,编译器会自动把它们合并成一个。

C++标准库都存放在一个名叫 std(standard) 的命名空间中。

二、C++的输入输出

(1)

是 Input Output Stream 的缩写,为你提供了输入输出 (cin、cout) 和操作规则 (<<、>> )。

(2)std::cin和std::cout

std::cin是在控制台输入的意思,我们知道 C++ 的标准库都放在 std 这个命名空间里。所以前面要加上 std::,这里面的 c 是 console(控制台) 的意思,in 是 input(输入的意思)。

std::cout与上面唯一的区别是 out 是输出的意思。所以表示的是在控制台输出的意思。

(3)<< 和 >>

<<是流插入运算符,和 cout 搭配使用。例如 std::cout<<"hello world"。把 hello world 在终端打印出来。可以一次打印多个内容。

#include <iostream>
int main() {
    using namespace std;
    cout << "hello world" << endl;
    cout << "我的刀盾喜欢奶龙" << endl << "咕咕嘎嘎" << endl; // 在屏幕上打印两行内容
}

是流提取运算符,和 cin 搭配使用。也可以一次输入多个内容。

#include <iostream>
int main() {
    using namespace std;
    int a, b;
    cout << "请输入两个整数:";
    cin >> a >> b;
    cout << "两个数之和为:" << a + b << endl;
}

需要注意的 C++ 可以自动识别变量类型,不需要我们手动输入占位符。

(4)endl

endl 表示换行的意思。

三、缺省参数

(1)基本概念

定义函数时,给定参数一个默认值 (这个值也叫做缺省值)。在传参数时,如果不传参数就使用默认值,传参数就使用你传的参数。

#include <iostream>
using namespace std;
void Print(int a= 3) {
    cout << a << endl;
}
int main() {
    Print(); // 打印 3
    Print(6); // 打印 6
}

(2)全缺省

给函数的全部参数设置缺省值。

#include <iostream>
using namespace std;
void Print(int a= 3,int b = 2) {
    cout << a << "," << b << endl;
}
int main() {
    Print(); // 打印 3,2
    Print(0,0); // 打印 0,0
}

(3)半缺省

给函数的部分参数设置缺省值。半缺省中,C++规定缺省值必须从右向左连续传。在使用时,必须传够没用缺省值的参数,且是按照从左向右传的顺序。

#include <iostream>
using namespace std;
void Print(int a, int b = 1, int c = 2) {
    cout << a << "," << b << ","<< c << endl;
}
int main() {
    //Print(); // 没有传够参数,会触发编译错误
    Print(0); // 打印 0,1,2 半缺省起码传一个
    Print(6,6); // 打印 6,6,2
    Print(5,5,5); // 打印 5,5,5
}

函数声明和定义分离时,函数的缺省参数只能出现一次,且出现在声明部分。

#include <iostream>
using namespace std;
void Print(int a, int b = 3); // 函数声明部分 (缺省值必须写在声明里)
void Print(int a , int b) { // 函数定义部分
    cout << a << "," << b << endl;
}
int main() {
    Print(3); // 打印 3,3
    Print(2,6); // 打印 2,6
}

四、函数重载

C++规定在同一作用域内,可以存在一个或多个同名函数。但是这个同名函数需要满足参数个数不同 || 参数类型不同 || 参数顺序不同 (参数类型的顺序不同)。

#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;
}
int main() {
    int a = Add(1,1,1);
    int b = Add(1, 1);
    cout << a << endl << b << endl;
}
#include <iostream>
using namespace std;
int Add(int x,int y) {//参数类型不同
    return x + y;
}
double Add(double x, double y) {
    return x + y;
}
int main() {
    int a = Add(2, 3);
    double b = Add(1.2, 1.3);
    cout << a << endl << b << endl;
}
#include <iostream>
using namespace std;//参数类型不同
double Calc(int a,double b) {
    return a + b;
}
double Calc(double a,int b) {
    return a - b;
}
int main() {
    double a = Calc(2, 2.2);
    double b = Calc(2.2, 2);
    cout << a << endl;//a 的参数第一个是整型,第二个是浮点型,所以调的是加法函数 (4.2)
    cout << b << endl;//b 的参数第一个是浮点型,第二个是整型,所以调的是减法函数 (0.2)
}

五、引用(reference)

(1)基本概念

给已有的变量起一个别名。直接在原内存上操作这个变量。

(2)语法

类型& 引用别名 = 引用对象;

以我们以前常写的 Swap 函数为例,我们来体会引用的妙处。

#include <iostream>
using namespace std;
void Swap(int* a, int* b) {//用指针的写法
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
int main() {
    int a = 2, b = 3;
    cout << "交换前" << "a = " << a << " " << "b = " << b << endl;
    Swap(&a, &b);
    cout <<"交换后" << "a = " << a << " " << "b = " << b << endl;
}
#include <iostream>
using namespace std;
void Swap(int& a, int& b) {//用引用的写法
    int tmp = a;
    a = b;
    b = tmp;
}
int main() {
    int a = 2, b = 3;
    cout << "交换前" << "a = " << a << " " << "b = " << b << endl;
    Swap(a, b);
    cout << "交换后" << "a = " << a << " " << "b = " << b << endl;
}

(3)引用的要求

①初始化

对于局部/全局使用引用时必须进行初始化。比如顺序表的初始化,在 main 函数内部使用引用。

#include <iostream>
using namespace std;
int main() {
    int a = 10;
    int& b = a; // 引用时必须进行初始化
    cout << &a << endl;
    cout << &b << endl; // 在这里可以看到 a,b 是同一个地址
}

对于函数形参里的引用,你传的实参就是已经完成了初始化。比如前面的 Swap 函数。你传完参数,其实就完成了对形参的初始化。

②命名

对于不同作用域下引用的别名可以相同,比如我们上面的 Swap 函数。同一作用域下引用的别名不能与原变量的名字相同。

③多个引用

一个变量可以有多个引用,一个引用的改变一定会改变原变量和其它引用的值。

#include <iostream>
using namespace std;
int main() {
    int a = 2;
    int& b = a;
    int& c = a; // 这里可以写 a 也可以写 b
    cout << "变化前" << a << ","<<b << "," << c << endl;
    c++;
    cout << "变化后" << a << "," << b << "," << c << endl; // 这里可以观察到
    //a,b,c 的值均发生了变化
}
④引用的绑定问题

引用一旦绑定某个实体 (有内存地址,能存储数据的对象;例如变量、数组),就终身只是这个实体的别名。再次对引用的操作,只是在修改引用的值,内存永远都是那一块。

int main() {
    int a = 2;
    int b = 3;
    int& ra = a;
    ra = b; // 只是赋值操作
    //int& ra = b; // 重定义错误
}
⑤引用的优点

引用在实践中往往用于函数传参或者做返回值。因为它直接对内存进行操作,就减少了拷贝从而提高了时间效率。

六、const 引用

(1)概念

被 const 修饰的引用。原数据进行 const 引用后权限只能不变或者变小。

(2)权限变化

原变量权限为只读,const 引用后权限还是只读。

int main() {
    const int a = 3; // 权限为只读,不能修改 a = 3 的值
    const int& ra = a; // 权限仍然为只读,不能修改 ra = 3 的值
    //int& ra = a; // 错误写法,权限不能被放大
}

原变量为可读可写,const 引用后权限为只读。

int main() {
    int a = 3; // 可读可写
    const int& ra = a; // 只读
    a = 6; // 正确写法,没有超出权限
    //ra = 3; // 错误写法,超出了权限
}

(3)const 引用修饰临时变量

①什么是临时变量

变量是指内存空间和存储的值。

临时变量是指为了保证代码能跑,编译器自己制定的一份临时空间。生命周期随着这条语句的执行结束立马销毁。

常见的有单独的常量 (表达式算出来没有用变量存储的也算),不同类型转化时触发的临时变量的创建。

②const 引用可以修饰临时变量的原因

对于普通的引用只能绑定有内存地址的变量。核心原因是普通的引用可读可写,对于临时变量这种临时产生的对象,本身就不安全。你还提升访问权限,这不就太过分了。

而 const 引用可以修饰临时变量的主要原因就是你临时变量虽然本身就不安全。反正我只读,都会把你改为安全的,反正不会对你进行操作。唯一的变化就是延长了临时变量的生命周期,const 引用什么时候销毁,临时变量什么时候销毁。

③const 引用修饰常量
int main() {
    const int& ra = 20; // 安全
    int& rra = 20; // 不安全,属于权限放大
}
int main() {
    int a = 20;
    const int& ra = a * 3; // 安全
    int& rra = a * 3; // 不安全,权限放大
}
④const 引用修饰不同类型转化
int main() {
    int a = 3;
    const double& ra = a; // 安全
    double& rra = a; // 不安全,权限放大
}

(4)引用和指针的区别

①语法:引用只是给变量取一个别名,不需要单独再开空间。而指针是存储地址的变量,所以需要单独开空间。

②初始化:引用在定义时必须进行初始化;而指针一般建议初始化,避免野指针。

③特性:引用在绑定一个对象后,就不能再改变;而指针绑定一个对象后可以重新绑定。

④访问:引用可以直接访问对象;而指针需要解引用才能访问对象。

⑤大小:引用的大小取决于对象的大小;指针的大小取决于操作系统的位数(32 位下占 4 个字节;64 位下占八个字节)

⑥安全性:指针很容易出现空指针和野指针;而引用不存在这个问题。

七、宏

(1)概念

宏是在预处理阶段,给一段文本 (值/表达式/代码) 绑定一个宏名(符号),分为有参宏和无参宏。

(2)无参宏

语法:

#define 宏名 替换文本

例子:

#define val 18
int main() {
    using namespace std;
    cout << val << endl; // 在执行程序时编译器会自动将 val 换成 18
}

(3)有参宏

语法:

#define 宏名 (参数 1,参数 2,……) 替换文本//括号里是参数列表

例子:

#define Add(a,b) ((a) + (b))
int main() {
    using namespace std;
    cout << Add(2, 3) << endl; // 输出 5
}

注意:这里 a 和 b 加括号,原因是为了避免运算符优先级带来的计算错误。

八、inline

(1)概念

被 inline 修饰的函数叫做内联函数。inline 的作用是将代码在调用处展开,不需要再建立栈帧了,提高了效率。

(2)注意

inline 只是建议,编译器可以采纳也可以不采纳。一般内联函数都是几行的小代码。

#include <iostream>
using namespace std;
inline int Add(int a,int b) {
    return a + b;
}
int main() {
    cout << Add(2, 3) << endl; // 就是这个意思 cout << 2+3 << endl;
}

(3)内联函数和宏的区别

①本质:内联函数是函数;宏是文本替换

②运算符优先级:内联函数不存在问题;宏需要手动添加括号

③调试:内联函数可以调试,宏不能调试

④编译器:编译器可以拒绝内联;编译器不能拒绝宏,宏是强制替换

九、nullptr

(1)概念

nullptr 是 C++11 引入的一个关键字,用来表示空指针。

(2)引入的原因

NULL 在 C++表示的是 0 的意思,如果在函数重载时,就会发生匹配歧义。

#include <iostream>
using namespace std;
void Print(int* x) {
    cout << "int*" << endl;
}
void Print(int x) {
    cout << "int" << endl;
}
int main() {
    Print(NULL); // 你预期的结果是 int,可是运行结果却是 int*
    Print(nullptr); // 符合预期结果
}

目录

  1. C++ 基础概念
  2. 一、命名空间
  3. (1)C++标识符查找规则
  4. (2)引起标识符命名冲突的本质原因
  5. (3)命名空间
  6. ①概念
  7. ②语法
  8. ③解决标识符冲突问题
  9. (4)命名空间的嵌套
  10. ①概念
  11. ②语法
  12. ③示例
  13. (5)命名空间的使用
  14. ①指定命名空间访问
  15. ②展开某个成员访问
  16. ③展开命名空间的全部成员
  17. (6)补充
  18. 二、C++的输入输出
  19. (1)<iostream>
  20. (2)std::cin和std::cout
  21. (3)<< 和 >>
  22. (4)endl
  23. 三、缺省参数
  24. (1)基本概念
  25. (2)全缺省
  26. (3)半缺省
  27. 四、函数重载
  28. 五、引用(reference)
  29. (1)基本概念
  30. (2)语法
  31. (3)引用的要求
  32. ①初始化
  33. ②命名
  34. ③多个引用
  35. ④引用的绑定问题
  36. ⑤引用的优点
  37. 六、const 引用
  38. (1)概念
  39. (2)权限变化
  40. (3)const 引用修饰临时变量
  41. ①什么是临时变量
  42. ②const 引用可以修饰临时变量的原因
  43. ③const 引用修饰常量
  44. ④const 引用修饰不同类型转化
  45. (4)引用和指针的区别
  46. 七、宏
  47. (1)概念
  48. (2)无参宏
  49. (3)有参宏
  50. 八、inline
  51. (1)概念
  52. (2)注意
  53. (3)内联函数和宏的区别
  54. 九、nullptr
  55. (1)概念
  56. (2)引入的原因
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • MinGW-w64 安装详细步骤(Windows GCC/G++编译器配置)
  • OpenClaw AI 物理级离线部署指南:Windows 环境配置与运行
  • VRChat 实时语音翻译工具 VRCT 功能与配置
  • PyTorch 显存优化与 Python 内存管理机制解析
  • Git 简介及基本操作
  • 单双序列动态规划问题详解
  • 代码最佳实践与指南(三):版本控制与重构
  • 编写提示词(Prompt)的实用技巧
  • C++23 常用特性详解
  • SCI 论文降低 AI 检测率的工具实测与方案
  • 个人开发者合法使用 JetBrains 的几种途径
  • ASP.NET 页面输出二进制图像方法
  • Rust + LLM 开发实战:构建智能命令行运维助手
  • OpenClaw 配合 cpolar 实现本地 AI 外网访问实战
  • VS Code 禁用 Copilot 代码补全功能
  • SSM 框架下基于 Web 的在线投稿系统设计与实现
  • SpringBoot 整合 Neo4j 图数据库实战指南
  • Claude Code 高级编程技巧实战项目详解
  • Milvus 实战:Attu 可视化安装与 Python 整合指南
  • Python ORM 框架:SQLAlchemy 完全指南

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online