c++11学习

跟随b站课程爱编程的大丙学习c++,进行记录

1:原始字符串字面量

它的主要作用:让字符串里的反斜杠、双引号和换行更容易书写,避免大量转义。

基本语法是:R"(字符串内容)":

std::string a = "F:\\robot\\config\\motor.yaml"; std::string b = R"(F:\robot\config\motor.yaml)";

输出:

F:\robot\config\motor.yaml

#include <iostream> #include <string> using namespace std; int main() { int motor_id = 1; string path = R"(F:\robot\motor.yaml)"; cout << "Motor ID: " << motor_id << '\n'; cout << path << '\n'; return 0; }

输出:

2:constexpr

constexpr变量:初始化值必须满足编译期常量表达式的要求。

constexpr函数:满足条件时可以在编译期计算,也可以在运行期调用。

  • 先分清“编译期”和“运行期”

    编译期是把代码编译成程序的阶段;运行期是程序启动后执行代码的阶段。

    int a = 6; // 数字 6 不需要运行程序就能知道 int b; std::cin >> b; // b 的值需要等用户输入后才知道

    constexpr关心的就是:这个值能不能提前确定?

  • 理解const和constexpr变量

    const表示初始化后不能修改;constexpr变量在此基础上,还要求初始化值满足编译期常量表达式的条件。

    constexpr int count = 6; // 正确 constexpr int total = count * 2; // 正确,结果为 12

    如果值来自用户输入:

    int number; std::cin >> number; const int a = number; // 正确:得到值后不再修改 // constexpr int b = number; // 错误:编译期不知道 number

    注意:const int a = 6;也可以是编译期常量。区别是const不保证,而constexpr明确要求。

  • 理解constexpr函数

    constexpr int square(int x) { return x * x; }

    它可以用于编译期计算:

    constexpr int result = square(5); // 必须在常量表达式中得到 25

    也可以接受运行期的值:

    int number; std::cin >> number; int result = square(number); // 正确:运行期计算

    **函数写了constexpr,不代表每次调用都在编译期执行。**要看传入的值和调用的使用场景。

  • 放到函数模板中,含义不变

    模板负责让同一套代码支持不同类型:

    template<typename T> constexpr T square(T x) { return x * x; }
    constexpr int a = square(3); // T 是 int,得到 9 constexpr double b = square(1.5); // T 是 double,得到 2.25

    这里,template负责类型通用,constexpr负责允许满足条件时的编译期计算。模板在编译期处理,不代表函数调用一定在编译期执行。

  • 放到构造函数中,是为了支持编译期初始化对象

    构造函数负责给对象的成员设置初始值:

    struct Point { int x; int y; constexpr Point(int a, int b) : x(a), y(b) { } };

    其中,: x(a), y(b)表示用a初始化x,用b初始化y。

    constexpr Point p(3, 4); // 在编译期初始化对象 constexpr int value = p.x; // 得到 3

    这个构造函数也能创建普通对象:

    int number; std::cin >> number; Point p(number, 4); // 正确:运行期初始化对象

    构造函数上的constexpr提供编译期初始化的能力;声明对象时的constexpr则要求这次初始化必须满足编译期条件。

3:auto自动推导

auto的作用是:让编译器根据初始化表达式,推导变量的类型。类型确定后,就不会再改变。

auto number = 10;

这里相当于:

int number = 10;

3.1:const修饰指针指向的对象:会保留

int number = 10; const int* p = &number; auto q = p; // q 的类型是 const int*

const int*表示:不能通过这个指针修改它指向的对象。

// *q = 20; // 错误:不能通过 q 修改 number q = nullptr; // 正确:q 自己可以改变指向

3.2:const修饰指针本身:不保留

const修饰指针本身:普通auto不保留

注意const的位置变了:

int number = 10; int* const p = &number; auto q = p; // q 的类型是 int*

int* const表示:指针p自己不能改变指向。

p不能修改指向,q可以修改指向

// p = nullptr; // 错误:p 自己不能修改 q = nullptr; // 正确:q 自己可以修改
原指针类型auto q = p;推导出的类型
const int*const int*
int* constint*
const int* constconst int*

3.3 auto&

const int number = 10; const int& r = number;

分别使用auto和auto&:

auto a = r; // int:复制一个值 auto& b = r; // const int&:继续引用原对象
a = 20; // 正确:a 是独立的、可以修改的 int // b = 20; // 错误:不能通过 b 修改原对象

决定是否按引用推导的,是声明中的auto&,不是右边的变量原本是不是引用。

auto&会根据被引用对象保留限定:

int x = 10; const int y = 20; auto& a = x; // int& auto& b = y; // const int&

3.4不能使用auto的场景

场景错误写法原因
普通局部变量没有初始化值auto x;没有依据,无法推导类型
同一条声明推导出不同类型auto a = 1, b = 2.5;一个推导为int,另一个为double
普通函数的参数〔C++17〕void show(auto x);C++17 不支持这种普通函数参数写法
普通非静态数据成员struct Motor { auto id = 1; };此处必须明确成员类型
直接代替容器元素类型std::vector<auto> values;必须提供具体元素类型
不能声明数组auto arr[3]={1,2,3}原生数组应明确写出元素类型

3.5常用的场景

第一种:迭代器类型较长时。

你已经学过map,可以比较下面两种写法:

std::map<int, std::string> names; std::map<int, std::string>::iterator it1 = names.begin(); auto it2 = names.begin();

it1和it2的类型相同。这里使用auto能省去冗长的类型名称。

第二种:范围for循环。

std::vector<std::string> names{"joint1", "joint2", "joint3"}; for (const auto& name : names) { std::cout << name << '\n'; }

这里的name是const std::string&,可以读取元素,也避免了每次复制字符串。

根据目的选择写法:

循环写法含义
for (auto value : values)每次复制一个元素
for (auto& value : values)直接访问元素,可以修改
for (const auto& value : values)直接访问元素,通过该引用只读

第三种:保存 Lambda 表达式。

后面学习回调函数时,会经常看到:

auto square = [](int x) { return x * x; }; std::cout << square(3); // 输出 9

Lambda 对象的具体类型由编译器生成,使用auto很方便。

4:decltype

decltype负责确定类型,右侧初始化表达式负责提供值或决定引用绑定谁。

4.1:基本用法:取得类型,不计算数值

decltype(表达式)会分析表达式的类型,但不会实际执行其中的计算。

int a = 10; decltype(a) b = 99; decltype(a + 3.14f) c = 52.13f; decltype(a + 1.2 * c) d = 520.1314;

结果如下所示:

int b = 99; float c = 52.13f; double d = 520.1314;

4.2:直接写变量名:取得变量声明时的类型

当decltype中直接写变量名时,会取得这个变量声明的类型,包括其中的const和引用。

int x = 99; const int& y = x; decltype(x) a1 = x; decltype(y) b1 = x;

相当于:int a1 = x;const int& b1 = x;

4.3:函数调用

函数返回方式对应调用的decltype结果
返回intint
返回int&int&
返回int&&int&&
返回const int&const int&
int n = 100; int func_int(); int& func_int_r(); int&& func_int_rr(); const int func_cint(); const int& func_cint_r(); const int&& func_cint_rr(); const Test func_ctest(); decltype(func_int()) a2 = 0; // int decltype(func_int_r()) b2 = n; // int& decltype(func_int_rr()) c2 = 0; // int&& decltype(func_cint()) d2 = 0; // int decltype(func_cint_r()) e2 = n; // const int& decltype(func_cint_rr()) f2 = 0; // const int&& decltype(func_ctest()) g2 = Test(); // const Test
decltype(func_cint()) d2 = 0; // int decltype(func_ctest()) g2 = Test(); // const Test

对于这里的内置类型int,按值返回时,调用表达式不会保留顶层const;而类类型const Test在这个例子中会保留。

4.4表达式是一个左值,或者被括号( )包围,使用 decltype推导出的是表达式类型的引用(如果有const、volatile限定符不能忽略)

#include <iostream> #include <vector> using namespace std; class Test { public: int num; }; int main() { const Test obj; //带有括号的表达式 decltype(obj.num) a = 0; decltype((obj.num)) b = a; //加法表达式 int n = 0, m = 0; decltype(n + m) c = 0; decltype(n = n + m) d = n; return 0; }

obj.num 为类的成员访问表达式,符合场景1,因此 a 的类型为int
obj.num 带有括号,符合场景3,因此b 的类型为 const int&。
n+m 得到一个右值,符合场景1,因此c的类型为 int
n=n+m 得到一个左值 n,符合场景3,因此d的类型为 int&

5:返回值后置

在编程中,在模板函数中需要知道返回类型:

#include <iostream> using namespace std; // R->返回值类型, T->参数1类型, U->参数2类型 template <typename R, typename T, typename U> R add(T t, U u) { return t + u; } int main() { int x = 520; double y = 13.14; // auto z = add<decltype(x + y), int, double>(x, y); auto z = add<decltype(x + y)>(x, y); // 简化之后的写法 cout << "z: " << z << endl; return 0; }

有时候并不知道函数内部具体返回是什么?可能会很复杂。

具体格式:

// 符号 -> 后边跟随的是函数返回值的类型 auto func(参数1, 参数2, ...) -> decltype(参数表达式)

auto 会追踪 decltype() 推导出的类型

#include <iostream> using namespace std; template <typename T, typename U> // 返回类型后置语法 auto add(T t, U u) -> decltype(t+u) { return t + u; } int main() { int x = 520; double y = 13.14; // auto z = add<int, double>(x, y); auto z = add(x, y); // 简化之后的写法 cout << "z: " << z << endl; return 0; }

6:final

C++中增加了final关键字来限制某个类不能被继承,或者某个虚函数不能被重写

如果使用final修饰函数,只能修饰虚函数,并且要把final关键字放到类或者函数的后面。

6.1修饰函数

如果使用final修饰函数,只能修饰虚函数,这样就能阻止子类重写父类的这个函数了:

class Base { public: virtual void test() { cout << "Base class..."; } }; class Child : public Base { public: void test() final { cout << "Child class..."; } }; class GrandChild : public Child { public: // 语法错误, 不允许重写 void test() { cout << "GrandChild class..."; } };

test()是基类中的一个虚函数,在子类中重写了这个方法,但是不希望孙子类中继续重写这个方法了,因此在子类中将test()方法标记为final,孙子类中对这个方法就只有使用的份了。

6.2:修饰类

使用final关键字修饰过的类是不允许被继承的,也就是说这个类不能有派生类。

class Base { public: virtual void test() { cout << "Base class..."; } }; class Child final: public Base { public: void test() { cout << "Child class..."; } }; // error, 语法错误 class GrandChild : public Child { public: };

7:overrid

确保重新写的函数是正确的

编译器都会指出:这个函数没有重写对应的基类虚函数。

class Base { public: virtual void test() { cout << "Base class..."; } }; class Child : public Base { public: void test() override { cout << "Child class..."; } }; class GrandChild : public Child { public: void test() override { cout << "Child class..."; } };

8:默认模板参数

8.1类模板默认参数

#include <iostream> using namespace std; template <typename T=int, T t=520> class Test { public: void print() { cout << "current value: " << t << endl; } }; int main() { Test<> t; t.print(); Test<int, 1024> t1; t1.print(); return 0; }

8.2:函数模板默认参数

#include <iostream> using namespace std; template <typename T=int> // C++98/03不支持这种写法, C++11中支持这种写法 void func(T t) { cout << "current value: " << t << endl; } int main() { func(100); return 0; }

当所有模板参数都有默认参数时,函数模板的调用如同一个普通函数。

但对于类模板而言,哪怕所有参数都有默认参数,在使用时也必须在模板名后跟随<>来实例化。

9:函数指针

先定义一个普通函数,用来计算两个整数的和:

int add(int a, int b) { return a + b; }

平时直接通过函数名调用:

int result = add(2, 3); // result 是 5

现在,我们用一个指针p指向这个函数:

p是一个函数指针,指向的函数接收两个int,返回一个int。

int (*p)(int, int) = add;
部分含义
(*p)p是一个指针
后面的(int, int)它指向的函数接收两个int参数
最前面的int这个函数返回int
= add让p指向add函数

有了p,就可以通过它调用add:

int result = p(2, 3); // result 是 5

因为p指向add,所以此时下面两种调用效果相同:

add(2, 3); // 通过函数名调用 p(2, 3); // 通过函数指针调用

完整代码:

#include <iostream> int add(int a, int b) { return a + b; } int main() { int (*p)(int, int) = add; std::cout << p(2, 3) << '\n'; // 输出 5 return 0; }

10:定义别名

在c++中可以通过typedef重新定义以给类型

typedef 旧的类型名 新的类型名;

使用using定义别名的语法格式是这样的:

using 新的类型 = 旧的类型; // 使用举例 using uint_t = int;

定义函数指针:

// 使用typedef定义函数指针 typedef int(*func_ptr)(int, double); // 使用using定义函数指针 using func_ptr1 = int(*)(int, double);

定义模块:

在定义模块别名中,使用typedef非常麻烦,在c++11中引入了using

template <typename T> using mymap = map<int, T>;

完整代码如下:

using namespace std; template <typename T> using mymap = map<int, T>; int main(void) { // map的value指定为string类型 mymap<string> m; m.insert(make_pair(1, "luffy")); m.insert(make_pair(2, "ace")); // map的value指定为int类型 mymap<int> m1; m1.insert(1, 100); m1.insert(2, 200); return 0; }

相关新闻

视觉模型重塑时间序列分析:从离散Token到连续视觉的范式转换

视觉模型重塑时间序列分析:从离散Token到连续视觉的范式转换

1. 从离散Token到连续视觉&#xff1a;时间序列分析的新思路拆解时间序列分析这个领域&#xff0c;做的人多&#xff0c;但真正让人眼前一亮的突破少。传统方法从统计模型一路走到深度学习&#xff0c;Transformer架构进来之后&#xff0c;大家发现一个尴尬的事实&#xff1a;文…

2026/10/20 5:21:04 阅读更多 →
向AI提交创作需求:关键信息清单助你生成优质博客

向AI提交创作需求:关键信息清单助你生成优质博客

抱歉&#xff0c;我还没有收到您的项目标题和相关描述。麻烦您将以下信息发给我&#xff0c;我立刻开始创作&#xff1a;项目标题: [在这里填写标题] 项目正文: [零散描述也可以] 关键词: [关键词1, 关键词2, ...] 摘要描述: [一句话简介]收到后我会直接输出一篇完整的、可直接…

2026/10/20 5:21:04 阅读更多 →
PyTorch nn.DataParallel原理与实战:多卡训练的底层基石

PyTorch nn.DataParallel原理与实战:多卡训练的底层基石

1. 为什么今天还要深挖nn.DataParallel&#xff1f;它真过时了吗&#xff1f;在 PyTorch 生态里&#xff0c;提到多卡训练&#xff0c;很多人第一反应是DistributedDataParallel&#xff08;简称 DDP&#xff09;&#xff0c;社区文档、新教程、论文复现代码几乎清一色推荐它。…

2026/10/20 5:21:04 阅读更多 →

最新新闻

从单体到弹性扩展:高并发架构改造的完整实战复盘

从单体到弹性扩展:高并发架构改造的完整实战复盘

1. 项目背景与架构需求拆解1.1 最初的系统&#xff0c;和它一步步暴露出的问题先说下背景。这个代号为"arch-system"的架构改造项目&#xff0c;源于团队负责的一条核心业务链路。最初的系统是典型的三层单体&#xff1a;一个应用服务承载所有接口&#xff0c;MySQL …

2026/10/20 6:03:23 阅读更多 →
PPT-Master:用PowerPoint构建业务操作系统的方法论

PPT-Master:用PowerPoint构建业务操作系统的方法论

1. “PPT-Master”不是软件名&#xff0c;而是一类人的生存状态最近在几个技术协作群和设计交流社区里&#xff0c;“PPT-Master”这个词高频出现&#xff0c;但没人把它当产品名说——它更像一句带点自嘲又透着狠劲的行业暗号。我第一次听到是在某次跨部门复盘会上&#xff0c…

2026/10/20 6:03:23 阅读更多 →
图灵奖60年:人机环境系统智能的演进与落地

图灵奖60年:人机环境系统智能的演进与落地

六十年前&#xff0c;那个以一位计算机先驱命名的奖项第一次颁出时&#xff0c;大概没有人想到&#xff0c;它会成为一部无声的“智能观变迁史”。这六十年间&#xff0c;获奖成果背后的工作其实都在回答同一个问题&#xff1a;机器到底怎样才算有智能&#xff1f;答案从“会算…

2026/10/20 6:03:23 阅读更多 →
浙江高考VB排序系列:冒泡与选择排序代码实现及应试技巧

浙江高考VB排序系列:冒泡与选择排序代码实现及应试技巧

1. 从一道排序题说起&#xff1a;为什么VB排序值得单独拎出来讲每年到了技术科目备考的冲刺阶段&#xff0c;总有一批同学在排序算法这块反复栽跟头。选择题里问“冒泡排序第三轮结束后序列长什么样”&#xff0c;填空题里给一段残缺代码让你补全循环边界&#xff0c;上机操作题…

2026/10/20 6:03:23 阅读更多 →
图灵奖六十年:从机器能否思考到人机环境系统智能的跃迁

图灵奖六十年:从机器能否思考到人机环境系统智能的跃迁

图灵奖整整六十年了。作为计算机科学领域最负盛名的荣誉&#xff0c;它这些年一直被当作衡量学术巅峰的标尺。可如果你把六十年来历届获奖者所代表的方向串成一条时间线&#xff0c;会发现一个远比"学术成就"更有意思的东西正在浮现&#xff1a;整个领域对"智能…

2026/10/20 6:03:23 阅读更多 →
主动学习新思路:损失预测模块如何精准筛选高价值样本

主动学习新思路:损失预测模块如何精准筛选高价值样本

1. 为什么主动学习要换一种采样思路做深度学习项目&#xff0c;尤其在数据标注预算有限的时候&#xff0c;大家最先想到的办法多半是“先随便标一部分&#xff0c;训练一版模型&#xff0c;再用模型挑一些‘难样本’送给标注员”。这套逻辑本身没问题&#xff0c;难就难在“难样…

2026/10/20 6:02:23 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →