Interview AiBoxInterview AiBox 实时 AI 助手,让你自信应答每一场面试
请介绍C++11中引入的主要新特性
题型摘要
C++11引入了众多现代化特性,包括:1)自动类型推导(auto)简化了复杂类型声明;2)基于范围的for循环提高了遍历容器的便利性;3)智能指针(unique_ptr, shared_ptr, weak_ptr)提供了更安全的内存管理;4)Lambda表达式支持匿名函数定义;5)右值引用和移动语义优化了资源转移性能;6)nullptr作为明确的空指针表示;7)强类型枚举(enum class)避免命名空间污染;8)constexpr支持编译时计算;9)统一初始化语法({})适用于各种类型;10)using关键字提供更清晰的类型别名定义;11)可变参数模板增强了模板灵活性;12)线程支持库实现标准多线程编程;13)新容器(array, forward_list, unordered容器)和算法丰富了标准库功能。这些特性使C++更现代化、安全且易用。
C++11中引入的主要新特性
C++11(曾被称为C++0x)是C++标准的一次重大更新,引入了许多现代化特性,显著提升了语言的表达能力、安全性和易用性。下面详细介绍C++11的主要新特性:
1. 自动类型推导(auto关键字)
C++11引入了auto关键字,允许编译器自动推导变量的类型,简化了代码编写,特别是对于复杂类型。
// C++11之前
std::vector<int>::iterator it = vec.begin();
// C++11之后
auto it = vec.begin(); // 编译器自动推导it的类型
优点:
- 减少代码冗余
- 提高代码可读性
- 方便处理复杂类型
2. 基于范围的for循环
C++11引入了更简洁的for循环语法,可以遍历容器和数组。
std::vector<int> vec = {1, 2, 3, 4, 5};
// C++11之前
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << std::endl;
}
// C++11之后
for (const auto& elem : vec) {
std::cout << elem << std::endl;
}
3. 智能指针
C++11引入了新的智能指针,替代了旧的auto_ptr,提供了更安全的内存管理。
3.1 unique_ptr
独占所有权的智能指针,不可复制,只能移动。
std::unique_ptr<int> ptr(new int(42));
// std::unique_ptr<int> ptr2 = ptr; // 错误,不可复制
std::unique_ptr<int> ptr3 = std::move(ptr); // 正确,可以移动
3.2 shared_ptr
共享所有权的智能指针,使用引用计数管理内存。
std::shared_ptr<int> ptr1(new int(42));
std::shared_ptr<int> ptr2 = ptr1; // 引用计数增加
3.3 weak_ptr
弱引用指针,不增加引用计数,用于解决shared_ptr的循环引用问题。
std::shared_ptr<int> ptr1(new int(42));
std::weak_ptr<int> weakPtr = ptr1; // 不增加引用计数
if (auto tmp = weakPtr.lock()) { // 尝试提升为shared_ptr
// 使用tmp
}
4. Lambda表达式
C++11引入了Lambda表达式,允许在代码中定义匿名函数,提高了代码的灵活性和简洁性。
// 基本语法
[capture](parameters) -> return_type { body }
// 示例
std::vector<int> vec = {1, 2, 3, 4, 5};
int sum = 0;
// 使用Lambda计算和
std::for_each(vec.begin(), vec.end(), [&sum](int n) {
sum += n;
});
// 带返回值的Lambda
auto add = [](int a, int b) -> int {
return a + b;
};
捕获方式:
[]:不捕获任何外部变量[=]:以值的方式捕获所有外部变量[&]:以引用的方式捕获所有外部变量[x, &y]:x以值的方式捕获,y以引用的方式捕获
5. 右值引用和移动语义
C++11引入了右值引用(&&)和移动语义,提高了性能,特别是在处理资源管理时。
// 右值引用
int&& rref = 42; // 42是右值
// 移动构造函数
class MyString {
private:
char* data;
public:
// 传统拷贝构造函数
MyString(const MyString& other) {
// 深拷贝
data = new char[strlen(other.data) + 1];
strcpy(data, other.data);
}
// 移动构造函数
MyString(MyString&& other) noexcept {
// 移动资源
data = other.data;
other.data = nullptr;
}
};
// std::move函数
std::string str1 = "Hello";
std::string str2 = std::move(str1); // 将str1的资源移动到str2
6. nullptr关键字
C++11引入了nullptr关键字,作为空指针的显式表示,替代了容易产生歧义的NULL或0。
// C++11之前
int* ptr = NULL; // NULL实际上是0
void func(int); // 函数重载
void func(int*);
func(NULL); // 调用func(int),可能不是期望的行为
// C++11之后
int* ptr = nullptr; // 明确的空指针类型
func(nullptr); // 调用func(int*),符合预期
7. 强类型枚举(Enum Class)
C++11引入了强类型枚举,解决了传统枚举的一些问题,如命名空间污染和隐式转换。
// 传统枚举
enum Color { RED, GREEN, BLUE };
int color = RED; // 允许隐式转换
// 强类型枚举
enum class Color { RED, GREEN, BLUE };
// int color = Color::RED; // 错误,不允许隐式转换
Color color = Color::RED; // 必须使用枚举类型
8. constexpr和常量表达式
C++11引入了constexpr关键字,允许在编译时计算表达式和函数,提高了性能。
// 常量表达式变量
constexpr int size = 10;
int arr[size]; // 合法,size是编译时常量
// 常量表达式函数
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
// 编译时计算
constexpr int result = factorial(5); // 在编译时计算
9. 统一初始化语法
C++11引入了统一的初始化语法,使用花括号{}进行初始化,适用于各种类型。
// 基本类型
int a{5};
// 容器
std::vector<int> vec{1, 2, 3, 4, 5};
// 类对象
class Point {
public:
int x, y;
};
Point p{10, 20};
// 动态分配数组
int* arr = new int[5]{1, 2, 3, 4, 5};
10. 类型别名(using关键字)
C++11引入了using关键字作为typedef的替代方案,提供了更清晰的类型别名定义方式,特别适用于模板别名。
// 基本类型别名
using Integer = int;
// 函数指针别名
using FuncPtr = void(*)(int);
// 模板别名(typedef无法实现)
template<typename T>
using Vec = std::vector<T>;
Vec<int> intVector; // 等同于 std::vector<int>
11. 可变参数模板
C++11引入了可变参数模板,允许模板接受可变数量的参数,提高了模板的灵活性。
// 可变参数模板定义
template<typename... Args>
void print(Args... args) {
// 递归终止函数
void print() {}
// 递归打印函数
template<typename T, typename... Rest>
void print(T first, Rest... rest) {
std::cout << first << std::endl;
print(rest...);
}
print(args...);
}
// 使用
print(1, "Hello", 3.14, 'a');
12. 线程支持库
C++11首次在标准中引入了线程支持库,提供了多线程编程的标准接口。
#include <thread>
#include <mutex>
#include <condition_variable>
// 创建线程
void thread_function() {
// 线程执行的代码
}
std::thread t(thread_function);
t.join(); // 等待线程结束
// 互斥量
std::mutex mtx;
mtx.lock();
// 临界区代码
mtx.unlock();
// 使用lock_guard自动管理锁
std::lock_guard<std::mutex> lock(mtx);
// 临界区代码
// 离开作用域时自动解锁
// 条件变量
std::condition_variable cv;
// 等待条件
std::unique_lock<std::mutex> lk(mtx);
cv.wait(lk, []{return ready;});
// 通知条件
ready = true;
cv.notify_one();
13. 新的容器和算法
C++11引入了新的容器和算法,丰富了标准库的功能。
13.1 新容器
std::array:固定大小的数组,比原生数组更安全std::forward_list:单向链表,比std::list更节省空间std::unordered_set和std::unordered_map:基于哈希表的无序容器
// std::array
std::array<int, 5> arr = {1, 2, 3, 4, 5};
// std::forward_list
std::forward_list<int> flist = {1, 2, 3, 4, 5};
// std::unordered_map
std::unordered_map<std::string, int> umap = {
{"one", 1},
{"two", 2},
{"three", 3}
};
13.2 新算法
std::all_of、std::any_of、std::none_of:检查范围内的元素是否满足条件std::find_if_not:查找不满足条件的第一个元素std::copy_if:条件复制std::move和std::move_backward:移动元素std::shuffle:随机打乱元素顺序
std::vector<int> vec = {1, 2, 3, 4, 5};
// 检查是否所有元素都大于0
bool all_positive = std::all_of(vec.begin(), vec.end(), [](int n) {
return n > 0;
});
// 复制所有偶数到新容器
std::vector<int> evens;
std::copy_if(vec.begin(), vec.end(), std::back_inserter(evens), [](int n) {
return n % 2 == 0;
});
14. 其他重要特性
14.1 委托构造函数
允许一个构造函数调用同一个类的其他构造函数。
class MyClass {
private:
int x, y;
public:
MyClass(int x, int y) : x(x), y(y) {}
// 委托构造函数
MyClass() : MyClass(0, 0) {}
MyClass(int x) : MyClass(x, 0) {}
};
14.2 继承构造函数
允许派生类直接使用基类的构造函数。
class Base {
public:
Base(int x) {}
Base(double y) {}
};
class Derived : public Base {
public:
using Base::Base; // 继承Base的构造函数
};
Derived d1(42); // 调用Base(int)
Derived d2(3.14); // 调用Base(double)
14.3 显式虚函数重写
使用override和final关键字明确标识虚函数重写,避免意外错误。
class Base {
public:
virtual void foo() {}
virtual void bar() {}
};
class Derived : public Base {
public:
void foo() override {} // 明确表示重写基类虚函数
void bar() final {} // 表示这是最终重写,派生类不能再重写
};
14.4 静态断言
编译时断言检查,如果条件不满足,编译失败。
static_assert(sizeof(int) == 4, "Int must be 4 bytes");
template<typename T>
void check_type() {
static_assert(std::is_integral<T>::value, "T must be integral type");
}
总结
C++11作为C++语言的一次重大更新,引入了大量现代化特性,显著提升了语言的表达能力、安全性和易用性。这些特性包括自动类型推导、基于范围的for循环、智能指针、Lambda表达式、右值引用和移动语义、nullptr、强类型枚举、constexpr、统一初始化语法、类型别名、可变参数模板、线程支持库以及新的容器和算法等。这些特性使C++变得更加现代化、安全且易于使用,同时也提高了代码的性能和可维护性。
参考资料:
思维导图
Interview AiBoxInterview AiBox — 面试搭档
不只是准备,更是实时陪练
Interview AiBox 在面试过程中提供实时屏幕提示、AI 模拟面试和智能复盘,让你每一次回答都更有信心。
AI 助读
一键发送到常用 AI
C++11引入了众多现代化特性,包括:1)自动类型推导(auto)简化了复杂类型声明;2)基于范围的for循环提高了遍历容器的便利性;3)智能指针(unique_ptr, shared_ptr, weak_ptr)提供了更安全的内存管理;4)Lambda表达式支持匿名函数定义;5)右值引用和移动语义优化了资源转移性能;6)nullptr作为明确的空指针表示;7)强类型枚举(enum class)避免命名空间污染;8)constexpr支持编译时计算;9)统一初始化语法({})适用于各种类型;10)using关键字提供更清晰的类型别名定义;11)可变参数模板增强了模板灵活性;12)线程支持库实现标准多线程编程;13)新容器(array, forward_list, unordered容器)和算法丰富了标准库功能。这些特性使C++更现代化、安全且易用。
智能总结
深度解读
考点定位
思路启发
相关题目
设计一个社交朋友圈系统,支持用户发布动态、好友查看动态等功能,请设计其数据结构和系统架构
朋友圈系统设计涉及数据结构和系统架构两个方面。数据结构包括用户表、好友关系表、动态表、媒体表、点赞表和评论表等。系统架构采用分层设计,包括客户端层、接入层、业务逻辑层、数据存储层和基础设施层。核心功能包括发布动态、获取好友动态、点赞评论等。性能优化方面考虑了缓存策略、数据库优化和服务优化。系统设计还考虑了功能扩展和技术扩展,以适应未来的发展需求。
请列举并解释进程间通信的方式。
进程间通信(IPC)是操作系统提供的重要机制,主要方式包括:管道(匿名/命名)、消息队列、共享内存、信号量、信号、套接字和文件映射。管道适用于父子进程通信;消息队列支持异步通信;共享内存是最快的IPC方式;信号量用于进程同步;信号适合异步通知;套接字最通用,可用于网络通信;文件映射支持数据持久化。不同方式各有优缺点,应根据具体场景选择。
请列举一些Linux常用命令及其用途
Linux常用命令按功能可分为八大类:文件和目录操作(ls, cd, cp, mv, rm)、文本处理(cat, grep, sed, awk)、系统信息管理(uname, top, df, free)、网络相关(ping, ssh, curl, netstat)、权限管理(chmod, chown, sudo)、进程管理(ps, kill, jobs)、搜索查找(find, locate, which)和压缩解压(tar, zip, gzip)。掌握这些命令是后端开发的基础技能,能够有效进行系统管理、文件处理、问题排查和日常开发工作。
请解释C++中虚函数的实现原理
C++中虚函数的实现原理主要依赖于虚函数表(vtable)和虚指针(vptr)。每个包含虚函数的类都有一个虚函数表,存储该类虚函数的地址;每个对象实例包含一个虚指针,指向其类的虚函数表。当通过基类指针或引用调用虚函数时,系统会通过虚指针找到虚函数表,再从表中获取实际要调用的函数地址,从而实现运行时多态。这种机制虽然有一定的性能开销,但为C++提供了强大的面向对象多态能力。
select,poll,epoll有什么区别
select、poll和epoll是三种I/O多路复用机制。select是最早的,有fd数量限制(1024),性能O(n);poll改进了select,移除了fd数量限制,但仍是O(n)性能;epoll是Linux特有的,性能O(1),支持大量连接,有水平触发和边缘触发两种模式。epoll通过回调机制和mmap内存共享实现了高效的事件通知,适合高并发场景,但不跨平台。select和poll适合少量连接或需要跨平台的场景。