C++学习:六个月从基础到就业——C++11/14:其他语言特性
C++学习:六个月从基础到就业——C++11/14:其他语言特性
本文是我C++学习之旅系列的第四十四篇技术文章,也是第三阶段"现代C++特性"的第六篇,主要介绍C++11/14中引入的其他重要语言特性。查看完整系列目录了解更多内容。
引言
在前几篇文章中,我们已经详细介绍了C++11/14引入的一些主要特性,如右值引用与移动语义、lambda表达式、auto类型推导、decltype关键字以及列表初始化。然而,C++11/14标准还引入了许多其他重要的语言特性,这些特性虽然不像前面几个那样被广泛讨论,但在日常编程中同样非常有用。
本文将介绍这些"其他语言特性",包括nullptr、constexpr、范围for循环、默认函数控制、枚举类等。这些特性共同构成了现代C++的基础,掌握它们对于编写更简洁、更安全、更高效的C++代码至关重要。
目录
- nullptr关键字
- constexpr关键字
- 范围for循环
- 默认函数控制
- override和final关键字
- 强类型枚举
- 用户定义字面量
- noexcept说明符
- thread_local存储类型
- 内联命名空间
- 总结
nullptr关键字
NULL的问题
在C++11之前,程序员通常使用NULL
宏或直接使用0
来表示空指针,这可能导致函数重载解析的歧义:
void foo(int i) { std::cout << "整数版本" << std::endl; }
void foo(char* p) { std::cout << "指针版本" << std::endl; }int main() {foo(0); // 调用foo(int)foo(NULL); // 在大多数实现中,也会调用foo(int)
}
nullptr的优势
C++11引入了nullptr
关键字,它是一个特殊的字面量,可以隐式转换为任何指针类型,但不能转换为整数类型:
void foo(int i) { std::cout << "整数版本" << std::endl; }
void foo(char* p) { std::cout << "指针版本" << std::endl; }int main() {foo(nullptr); // 明确调用foo(char*)// 可以隐式转换为任何指针类型int* p1 = nullptr;char* p2 = nullptr;// 但不能转换为整数// int n = nullptr; // 编译错误
}
nullptr
的类型是std::nullptr_t
,可用于重载区分和模板参数匹配,提高了代码的类型安全性和可读性。
constexpr关键字
constexpr
关键字允许在编译期计算表达式的值,提供了真正的常量表达式功能。
编译期常量
// 编译期常量
constexpr int MAX_SIZE = 100;// 可用于数组大小
constexpr int getSizeForArray() { return 42; }
int array[getSizeForArray()]; // 合法:在编译期求值
constexpr函数
C++11中的constexpr
函数有很多限制,只能包含简单的代码:
// C++11 constexpr函数
constexpr int factorial(int n) {return n <= 1 ? 1 : (n * factorial(n - 1));
}// 编译期计算
constexpr int fact5 = factorial(5); // 编译期计算为120
C++14中的增强
C++14大大放宽了对constexpr
函数的限制,允许使用循环、条件语句等:
// C++14 constexpr函数
constexpr int factorial(int n) {int result = 1;for (int i = 1; i <= n; ++i) {result *= i;}return result;
}
应用场景
constexpr
的主要应用包括:
-
编译期数学计算
constexpr double circleArea(double r) {return 3.14159 * r * r; }
-
类型特性和元编程
template<typename T> constexpr bool is_power_of_two(T x) {return x > 0 && (x & (x - 1)) == 0; } static_assert(is_power_of_two(16), "16是2的幂");
-
提高性能:可编译期计算的内容不会增加运行时开销
范围for循环
基本语法
C++11引入了范围for循环,使迭代容器和数组更加方便:
// 数组迭代
int arr[] = {1, 2, 3, 4, 5};
for (int value : arr) {std::cout << value << " ";
}// 容器迭代
std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
for (const auto& name : names) { // 使用引用避免复制std::cout << name << " ";
}// 修改元素
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (auto& num : numbers) {num *= 2; // 每个元素乘以2
}
范围for循环的一般语法是:for (declaration : expression) { ... }
与迭代器的对比
相比传统迭代器方法,范围for循环更简洁,更不易出错:
// 传统迭代器方法
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {*it *= 2;
}// 范围for循环
for (auto& elem : vec) {elem *= 2;
}
自定义类型支持
要使自定义类型支持范围for循环,需要提供begin()
和end()
函数:
class IntegerRange {
private:int start;int end;class Iterator {// 实现迭代器接口...};public:IntegerRange(int s, int e) : start(s), end(e) {}Iterator begin() const { return Iterator(start); }Iterator end() const { return Iterator(end); }
};// 使用
for (int i : IntegerRange(1, 6)) {std::cout << i << " "; // 输出: 1 2 3 4 5
}
默认函数控制
C++11引入了=default
和=delete
来更精确地控制特殊成员函数的生成。
default关键字
显式要求编译器生成默认版本的特殊成员函数:
class Example {
public:// 显式要求生成默认构造函数Example() = default;// 自定义构造函数Example(int val) : value(val) {}// 显式要求生成默认析构函数和拷贝操作~Example() = default;Example(const Example&) = default;Example& operator=(const Example&) = default;private:int value = 0;
};
delete关键字
禁止使用特定函数:
class NonCopyable {
public:NonCopyable() = default;// 禁止拷贝NonCopyable(const NonCopyable&) = delete;NonCopyable& operator=(const NonCopyable&) = delete;// 允许移动NonCopyable(NonCopyable&&) = default;NonCopyable& operator=(NonCopyable&&) = default;
};// 禁止特定类型的隐式转换
class NoInt {
public:NoInt(double d) {} // 允许从double构造NoInt(int) = delete; // 禁止从int构造
};
实际使用场景
这些关键字在以下场景非常有用:
- 实现单例模式
- RAII资源包装器
- 禁止特定用法:如禁止在堆上创建对象
// 禁止在堆上创建对象
class NoHeapAllocation {
public:void* operator new(size_t) = delete;void* operator new[](size_t) = delete;
};
override和final关键字
override关键字
override
关键字用于显式标记覆盖基类的虚函数,帮助避免常见错误:
class Base {
public:virtual void foo() { std::cout << "Base::foo()" << std::endl; }virtual void bar(int x) { std::cout << "Base::bar()" << std::endl; }
};class Derived : public Base {
public:// 明确标记为覆盖,编译器会检查void foo() override { std::cout << "Derived::foo()" << std::endl; }// 如果参数不匹配,编译器会报错// void bar(double x) override { /* 错误:没有覆盖基类函数 */ }
};
final关键字
final
关键字应用于类或虚函数,禁止进一步继承或覆盖:
class Base {
public:virtual void foo() { std::cout << "Base::foo()" << std::endl; }
};class Derived : public Base {
public:// 禁止进一步覆盖此函数void foo() override final { std::cout << "Derived::foo()" << std::endl; }
};// 定义为final的类不能被继承
class FinalClass final {// ...
};
强类型枚举
传统枚举的问题
C++98/03中的传统枚举存在作用域污染、类型不安全等问题:
enum Color { RED, GREEN, BLUE };
enum Fruit { APPLE, BANANA, ORANGE };// 问题:枚举值会泄漏到全局命名空间
bool comparison = (RED == APPLE); // 允许比较,都是0
enum class的优势
C++11引入的强类型枚举解决了这些问题:
enum class Color { RED, GREEN, BLUE };
enum class Fruit { APPLE, BANANA, ORANGE };// 必须使用作用域操作符
Color c = Color::RED;// 不同枚举类型不能直接比较
// bool comparison = (Color::RED == Fruit::APPLE); // 编译错误// 不会隐式转换为整数
// int n = Color::GREEN; // 编译错误
int n = static_cast<int>(Color::GREEN); // 正确,显式转换
底层类型与前向声明
可以指定枚举的底层类型,并支持前向声明:
// 指定底层类型
enum class SmallEnum : uint8_t { A, B, C };// 前向声明
enum class Status : int; // 必须指定底层类型
用户定义字面量
C++11允许为自定义类型创建字面量,通过定义特殊的字面量运算符:
// 距离字面量
Distance operator"" _km(long double km) {return Distance(km * 1000.0); // 转换为米
}// 使用
auto marathon = 42.195_km; // 创建Distance对象
C++14标准库添加了多个字面量:
using namespace std::literals;// 字符串字面量
auto str = "hello"s; // std::string,不是C风格字符串// 时间字面量
auto day = 24h;
auto minute = 1min;// 复数字面量
auto c = 3.0 + 4.0i; // 复数(3, 4)
noexcept说明符
noexcept
说明符指定函数不会抛出异常:
// 保证不抛出异常的函数
void safeOperation() noexcept {// 如果这里抛出异常,程序会立即终止
}// 条件noexcept
template<typename T>
void swap(T& a, T& b) noexcept(noexcept(T(std::move(a)))) {T temp = std::move(a);a = std::move(b);b = std::move(temp);
}
noexcept
在移动语义中特别重要,标准库容器使用它来决定是否使用移动操作:
// 移动构造函数标记为noexcept
Widget(Widget&& other) noexcept: name_(std::move(other.name_)),data_(std::move(other.data_)) {
}
thread_local存储类型
thread_local
指定变量的存储持续性为线程生命周期,每个线程有自己的副本:
// 每个线程都有独立副本
thread_local int counter = 0;void threadFunction() {++counter; // 只影响当前线程的counterstd::cout << "Thread " << std::this_thread::get_id() << ": " << counter << std::endl;
}
应用场景包括:
- 线程安全的单例模式
- 线程专用缓存
- 无锁数据结构
内联命名空间
C++11引入了内联命名空间,简化版本管理和符号导出:
namespace MyLib {// v1命名空间内的符号直接可见inline namespace v1 {void func() { /* v1实现 */ }}// v2命名空间需要显式访问namespace v2 {void func() { /* v2实现 */ }}
}// 直接使用v1版本
MyLib::func(); // 调用MyLib::v1::func// 显式使用v2版本
MyLib::v2::func();
应用场景包括:
- 库版本管理
- 特性切换
- 平台特定实现
总结
C++11/14引入的这些"其他语言特性"极大地提高了C++语言的表达能力和安全性:
- nullptr:提供类型安全的空指针字面量
- constexpr:允许编译期计算表达式,增强性能和元编程能力
- 范围for循环:简化容器迭代,提高代码可读性
- 默认函数控制:通过
default
和delete
精确控制特殊成员函数 - override和final:增强类继承体系的安全性和表达能力
- 强类型枚举:提供更类型安全的枚举类型
- 用户定义字面量:为自定义类型创建直观的字面量表示法
- noexcept:明确函数的异常保证,优化移动语义
- thread_local:提供线程专用存储,简化多线程编程
- 内联命名空间:简化库版本管理和符号导出
掌握这些新特性,能够帮助我们编写更加现代化、高效、安全的C++代码。它们虽然各自看起来只是小改进,但共同提供了更强大、更具表达力的语言工具集。
这是我C++学习之旅系列的第四十四篇技术文章。查看完整系列目录了解更多内容。
相关文章:
C++学习:六个月从基础到就业——C++11/14:其他语言特性
C学习:六个月从基础到就业——C11/14:其他语言特性 本文是我C学习之旅系列的第四十四篇技术文章,也是第三阶段"现代C特性"的第六篇,主要介绍C11/14中引入的其他重要语言特性。查看完整系列目录了解更多内容。 引言 在前…...

【Linux笔记】——线程池项目与线程安全单例模式
🔥个人主页🔥:孤寂大仙V 🌈收录专栏🌈:Linux 🌹往期回顾🌹: 【Linux笔记】——简单实习一个日志项目 🔖流水不争,争的是滔滔不息 一、线程池设计二…...
数据驱动的社会舆情监测与分析——用算法洞察世界脉动
数据驱动的社会舆情监测与分析——用算法洞察世界脉动 在信息爆炸的时代,社会舆情的变化可以在极短时间内产生深远影响。从企业品牌到公共政策,社交媒体和新闻平台上的讨论能够直接影响决策者的策略制定。因此,数据驱动的舆情监测与分析 逐渐成为政府、企业以及社会机构的重…...
OD 算法题 B卷 【最佳植树距离】
文章目录 最佳植树距离 最佳植树距离 在直线的公路上种树,给定坑位数量和位置,及需要种多少棵树苗;树苗之间的最小距离是多少时,可以保证种的最均匀(树苗之间的最小距离最大); 输入描述&#…...

ZooKeeper 原理解析及优劣比较
大家好,这里是架构资源栈!点击上方关注,添加“星标”,一起学习大厂前沿架构! 引言 在分布式系统中,服务注册、配置管理、分布式锁、选举等场景都需要一个高可用、一致性强的协调服务。Apache ZooKeeper 凭…...
实战5:个性化数字艺术生成与销售
盈利思路 数字艺术销售: 平台销售:将生成的数字艺术作品上传到像OpenSea、Foundation等NFT平台进行售卖。每一件独特的艺术品可以通过NFT技术保证其唯一性,吸引收藏家和投资者。 定价策略:根据作品的复杂度、创意性以及市场需求来…...

是德科技 | 单通道448G未来之路:PAM4? PAM6? PAM8?
内容来源:是德科技 随着数据中心规模的不断扩大以及AI大模型等技术的兴起,市场对高速、大容量数据传输的需求日益增长。例如,AI训练集群中GPU等设备之间的互联需要更高的传输速率来提升效率。在技术升级方面,SerDes技术的不断进步…...

OceanBase 开发者大会,拥抱 Data*AI 战略,构建 AI 数据底座
5 月 17 号以“当 SQL 遇见 AI”为主题的 OceanBase 开发者大会在广州举行,因为行程的原因未能现场参会,仍然通过视频直播观看了全部的演讲。总体来说,这届大会既有对未来数据库演进方向的展望,也有 OceanBase 新产品的发布&#…...

STM32IIC协议基础及Cube配置
STM32IIC协议基础及Cube配置 一,IC协议简介1,核心特点2,应用场景 二,IC协议基础概念1,总线结构2,主从架构3,设备寻址4,起始和停止条件5,数据传输6,应答机制 三…...

CNN vs ViT:图像世界的范式演进
一、图像建模,是不是也可以“大一统” 在前文中我们提到,多模态大模型打破“只能处理文字”的限制。 在 NLP 世界里,Transformer 已经证明自己是理解语言的王者。那么在图像世界,我们是否也能有一种“通用架构”,让模…...

cocos creator使用jenkins打包微信小游戏,自动上传资源到cdn,windows版运行jenkins
cocos 版本2.4.11 在windows上jenkins的具体配置和部署,可参考上一篇文章cocos creator使用jenkins打包流程,打包webmobile_jenkins打包,发布,部署cocoscreator-CSDN博客 特别注意,windows上运行jenkins需要关闭windows自己的jenkins服务&a…...

定时器的两种实现方式
1、基于优先级队列/堆 队列是先进先出,优先级队列是优先级越高就存放在队列之前,我们可以将过期时间越早设置为优先级越高,那么临近过期时间的任务就会在队列前面,距离过期时间越晚的任务就在队列后面。 可以分配一个线程&#…...
Python、Pytorch、TensorFlow、Anconda、PySide、Jupyter
一、Python Python是一种高级、通用、解释型的开源编程语言,由Guido van Rossum于1990年代初设计。它具有以下显著特点: 1.语言特性 (1) 语法简洁易读,接近自然语言(如print(“Hello World!”)) (2) 采用强制缩进而非大括号定义代码块 (3) 支持面向对象、函数式和过…...

[Java实战]Spring Boot整合MinIO:分布式文件存储与管理实战(三十)
[Java实战]Spring Boot整合MinIO:分布式文件存储与管理实战(三十) 一、MinIO简介与核心原理 MinIO 是一款高性能、开源的分布式对象存储系统,兼容 Amazon S3 API,适用于存储图片、视频、日志等非结构化数据。其核心特…...
MacBook Air A2179(Intel版)安装macOS Catalina所需时间
MacBook Air A2179(Intel版)安装macOS Catalina所需时间如下: 一、标准安装时间范围 常规安装(通过App Store) • 下载时间:约30-60分钟(取决于网络速度,安装包约8GB) •…...

AI在人力资源领域的应用:把握时代浪潮
借鉴历史经验,引领技术变革 历史总是呈现出惊人的相似性。十年前,众多企业未能及时洞察移动技术与社交技术的潜在价值,迟迟没有将这些创新引入职场环境。随着时间推移,这些组织才意识到BYOD(自带设备办公)…...
【VxWorks 实时操作系统(RTOS)】常用函数汇总
VxWorks 实时操作系统(RTOS)中的核心函数 1. taskSpawn 函数 功能:用于动态创建并激活一个新任务(线程)。参数解析(以 VxWorks 为例):int taskSpawn(char *name, // 任务名…...

vr制作公司提供什么服务?
随着科技的迅猛进步,虚拟现实(Virtual Reality,简称VR)技术已经悄然渗透到我们的日常生活与工作中,成为推动数字化转型的重要力量。VR制作公司,作为前沿领域的探索者和实践者,以专业的技术和创新…...

下一代电子电气架构(EEA)的关键技术
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…...

matlab慕课学习3.5
于20250520 3.5 用while 语句实现循环结构 3.5.1while语句 多用于循环次数不确定的情况,循环次数确定的时候用for更为方便。 3.5.2break语句和continue语句 break用来跳出循环体,结束整个循环。 continue用来结束本次循环,接着执行下一次…...
大语言模型(LLM)如何通过“思考时间”(即推理时的计算资源)提升推理能力
大语言模型(LLM)如何通过“思考时间”(即推理时的计算资源)提升推理能力 核心围绕人类思维机制、模型架构改进、训练方法优化等展开 一、人类思维的启发:快思考与慢思考 类比心理学: 人类思维分两种模式: 快思考(系统1):直觉驱动,快速但易出错(如估算简单问题)。…...
Ollama 如何在显存资源有限的情况下合理分配给不同的服务?
在 Windows PowerShell 中启动两个 Ollama 实例的推荐步骤是: 打开第一个 PowerShell 窗口,并执行: $env:OLLAMA_HOST"0.0.0.0:11434" ollama serve打开第二个 PowerShell 窗口,并执行: $env:OLLAMA_HOST&qu…...

Qt音视频开发过程中一个疑难杂症的解决方法/ffmpeg中采集本地音频设备无法触发超时回调
一、前言 最近在做实时音视频通话的项目中,遇到一个神奇的问题,那就是用ffmpeg采集本地音频设备,当音频设备拔掉后,采集过程会卡死在av_read_frame函数中,尽管设置了超时时间,也设置了超时回调interrupt_c…...
基于注意力机制与iRMB模块的YOLOv11改进模型—高效轻量目标检测新范式
随着深度学习技术的发展,目标检测在自动驾驶、智能监控、工业质检等场景中得到了广泛应用。针对当前主流目标检测模型在边缘设备部署中所面临的计算资源受限和推理效率瓶颈问题,YOLO系列作为单阶段目标检测框架的代表,凭借其高精度与高速度的平衡优势,在工业界具有极高的应…...

PEFT库PromptTuningConfig 配置
PEFT库 PromptTuningConfig 配置 "Prompt Tuning"的参数高效微调 PromptTuningConfig 核心参数解析 1. task_type="CAUSAL_LM" 作用:指定任务类型为因果语言模型(Causal LM)。说明:因果语言模型从左到右生成文本(如GPT系列),这与任务需求匹配(模…...

操作系统----软考中级软件工程师(自用学习笔记)
目录 1、计算机系统层次结构 2、程序顺序执行的特征 3、程序并发执行的特征 4、三态模型 5、同步与互斥 6、信号量机制 7、PV操作 8、死锁 9、进程资源图 10、死锁避免 11、线程 12、程序局部性原理 13、分页存储管理 14、单缓冲器 15、双缓冲区 16、磁盘调度算…...
SQL 多表关联与分组聚合:解密答题正确率分析
一、问题拆解:从业务需求到SQL逻辑 1.1 需求分析 题目要求:计算浙江大学用户在不同难度题目下的答题正确率,并按正确率升序排序。 关键分析点: 数据来源: user_profile:存储用户信息(大学&a…...

基于 Redis 实现短信验证码登录功能的完整方案
🧱 一、技术栈与依赖配置 使用 Spring Boot Redis 实现短信验证码登录,以下是推荐的 Maven 依赖: <dependencies><!-- Spring Boot Web --><dependency><groupId>org.springframework.boot</groupId><ar…...

电平匹配电路
1、为什么要电平匹配? 现在很多SOC器件为了降低功耗,都把IO口的电平设计成了1.8V,核电压0.85V,当这种SOC做主平台时,在做接口设计需要格外关注电平的匹配。单板中经常需要将1.8V的电平转换成3.3V或者转成5V。如果没有注意到输入和输出信号之间的电平匹配,系统就无法正常…...

JavaScript 日志和调试工具箱-logger2js
原创功能丰富的 JavaScript 日志和调试工具箱,设计这个工具时考虑到了多种实际开发中的需求。该工具不仅提供了高效强大的日志输出显示功能,还包含了界面风格配置、代码格式化、事件处理、性能测试、方法调用栈输出,右键菜单、控制台显示控制…...