5分钟掌握Res-Downloader:跨平台网络资源嗅探下载实用指南
2026/5/23 14:18:14
目录
引言
一. 新的类功能
1.1 默认的移动构造和移动赋值
1.2 成员变量声明时给缺省值
1.3 default与delete
1.4 final与override
1.5 委托构造函数
1.6 继承构造函数
二. STL中的一些变化
三. lambda
3.1 lambda表达式语法
3.2 捕捉列表
3.3 lambda的应用
3.4 lambda的原理
四. 包装器
4.1 function
4.2 bind
总结
C++11 是现代 C++ 的奠基版本,它不仅补齐了长期存在的语言缺陷,还为泛型编程、对象语义管理、高性能编程等领域提供了全新的抽象方式。无论你是进行底层系统开发、构建高性能服务器,还是实现通用库组件,C++11 都是绕不开的一道坎。
class Person { public: Person(const char* name = "张三", int age = 19) :_name(name) , _age(age) { } /*Person(const Person& p) :_name(p._name) ,_age(p._age) {}*/ /*Person& operator=(const Person& p) { if(this != &p) { _name = p._name; _age = p._age; } return *this; }*/ /*~Person() {}*/ private: bit::string _name; int _age; }; int main() { Person s1; Person s2 = s1; Person s3 = std::move(s1); Person s4("xxx", 1); s4 = std::move(s2); return 0; }在最开始类和对象中已经奖结果讲解过,如果遗忘,点击复习【C++】类和对象
class Person { public: Person(const char* name = "张三", int age = 19) :_name(name) , _age(age) { } // default:解决 “自定义某个函数后,默认函数消失” 的问题 // 注意:在VS中这三个如果要生成就要一起生成 //Person(const Person& p) = default; //Person(Person&& p) = default; //Person& operator=(const Person& p) = default; // 一些类不期望被拷贝 // C++11 //Person(const Person& p) = delete; ~Person() {} private: // C++98:只声明(声明为私有),不实现 //Person(const Person& p); bit::string _name; int _age; }; int main() { Person s1; Person s2 = s1; Person s3 = std::move(s1); Person s4("xxx", 1); s4 = std::move(s2); return 0; }在之前已经讲解过,如果遗忘,点击复习【C++】多态
class Example { public: Example(int a, int b) :_x(a) , _y(b) { cout << "目标构造函数\n"; } Example(int a) : Example(a, 0) { cout << "委托构造函数\n"; } int _x; int _y; }; class Time { public: // 所有参数都会走初始化列表,虽然这里没有写second,但是second也会走这里的初始化列表初始化 // 初始化所有成员 Time(int h, int m) :_hour(h) , _minute(m) {} // error C3511: “Time”: 对委托构造函数的调用应仅为成员初始值设定项 // error C2437 : “_second”: 已初始化 Time(int h, int m, int s) :Time(h, m) // , _second(s) {} private: int _hour; int _minute; int _second = 0; }; int main() { Example(1, 2); Example(1); return 0; }class Base { public: Base(int x, double d) :_x(x) , _d(d) {} Base(int x) :_x(x) {} Base(double d) :_x(d) {} protected: int _x = 0; double _d = 0; }; // 传统的派生类实现构造 //class Derived : public Base { //public: // Derived(int x) : Base(x) {} // Derived(double d) : Base(d) {} // Derived(int x, double d) : Base(x, d) {} //}; // C++11继承基类的所有构造函数 class Derived : public Base { public: // 继承构造 // 继承了父类的所有构造,可以理解为编译器帮我们生成了上面的三个构造 using Base::Base; // 这样的话,自己的成员就无法初始化了,因为无法传参,所以只能用缺省值 // 所以如果有自己的成员,最好自己写构造 /*protected: int _i = 0; string _s;*/ // 派生类有自己的成员时,不适合用继承构造 // 综上:继承构造适用于派生类没有成员,或者是有成员,但是不用显示给值,只用缺省值即可 }; int main() { Derived d1(1); Derived d2(1.1); Derived d3(2, 2.2); return 0; }如有遗忘,可点击复习【C++】unorderedset/map
// 尾置返回类型lambda和普通函数都有 // 尾置返回类型,auto用于占位;这样如果返回类比较长,更容易看出看出函数名 std::map<std::string, std::pair<std::string, std::string>>::iterator func(); auto func()->std::map<std::string, std::pair<std::string, std::string>>::iterator; int main() { // 一个简单的lambda表达式 // 匿名函数对象 // 可以像函数一样使用,底层是一个仿函数 //auto add1 = [](int x, int y)->int {return x + y; }; auto add1 = [](int x, int y) {return x + y; }; // 返回类型可以省略,编译器会自动推导;但是写出来更清晰 cout << add1(1, 2) << endl; //cout << [](int x, int y)->int {return x + y; }(1, 2) << endl; // 不会这样用 // 1、捕捉为空也不能省略 // 2、参数为空可以省略 // 3、返回类型可以省略,可以通过返回对象自动推导 // 4、函数体不能省略 auto func1 = [] { cout << "hello bit" << endl; return 0; }; func1(); int a = 0, b = 1; auto swap1 = [](int& x, int& y) { int tmp = x; x = y; y = tmp; }; swap1(a, b); cout << a << ":" << b << endl; return 0; }int x = 0; // lambda写在全局,捕捉列表必须为空,因为全局变量不用捕捉就可以用,没有可被捕捉的变量 auto func1 = []() { x++; }; // 在一个类的成员函数中写lambda class A { public: void func() { int x = 0, y = 1; // 隐式传值捕捉,默认除了捕捉x和y,也把this也捕捉过来了(注:只有用了才会捕捉,这里的意思是this也能捕捉) // 可以捕捉_a1和_a2,虽然不属于当前的局部域,可以理解为把this捕捉了,因为_a1和_a2是通过this访问的 auto f1 = [=] { _a1++; // 可以修改 return x + y + _a1 + _a2; }; cout << f1() << endl; // 隐式引用捕捉同上 auto f2 = [&] { x++; _a1++; // 可以修改 return x + y + _a1 + _a2; }; cout << f2() << endl; // 捕捉this本质是可以访问成员变量 //auto f3 = [x] // 如果显示传值捕捉只捕捉x,则不能访问_a1和_a2,因为没有this //auto f3 = [x, _a1] // err:这样也不行 auto f3 = [x, this] { _a1++; // 可以修改 return x + _a1 + _a2; }; cout << f3() << endl; } private: int _a1 = 0; int _a2 = 1; }; int main() { // 只能用当前lambda局部域捕捉的对象和全局对象 // 捕获列表的意义,本质更方便的使用当前局部域的对象 int a = 0, b = 1, c = 2, d = 3; auto func1 = [a, &b] // 这里不是取地址,而是引用捕捉 { // 值捕捉的变量不能修改,引用捕捉的变量可以修改 //a++; // 这里的a是外面a的拷贝,默认是const不能修改 b++; // 引用捕捉,这里对b的修改就是对外面b的修改 int ret = a + b; x++; return ret; }; // 传值捕捉加mutable就可以修改(一般不会加) //auto func1 = [a, &b] () mutable // 用mutable必须加参数列表 // { // // 值捕捉的变量不能修改,引用捕捉的变量可以修改 // a++; // 这里的a是外面a的拷贝,加mutable就可以修改,注意:传值捕捉里面改变不影响外面 // b++; // 引用捕捉,这里对b的修改就是对外面b的修改 // int ret = a + b; // x++; // return ret; // }; cout << func1() << endl; // 隐式值捕捉 // 用了哪些变量就捕捉哪些变量(所有都能用) auto func2 = [=] { int ret = a + b + c + d; return ret; }; cout << func2() << endl; // 隐式引用捕捉 // 用了哪些变量就捕捉哪些变量(所有都能用) auto func3 = [&] { a++; c++; d++; }; func3(); cout << a << " " << b << " " << c << " " << d << endl; // 混合捕捉1 // a和b值捕捉,其他都是引用捕捉 //auto func4 = [=, a, b] err //auto func4 = [a, &, b] err auto func4 = [&, a, b] { // 值捕捉不能修改 //a++; //b++; c++; d++; return a + b + c + d; }; func4(); cout << a << " " << b << " " << c << " " << d << endl; // 混合捕捉2 // a和b引用捕捉,其他都是值捕捉 auto func5 = [=, &a, &b] { a++; b++; /*c++; d++;*/ return a + b + c + d; }; func5(); cout << a << " " << b << " " << c << " " << d << endl; // 局部的静态和全局变量不能捕捉,也不需要捕捉 // 可以直接使用,因为他们的作用域/生命周期是全局的 static int m = 0; auto func6 = [] { int ret = x + m; return ret; }; // 传值捕捉本质是一种拷贝,并且被const修饰了 // mutable相当于去掉const属性,可以修改了 // 但是修改了不会影响外面被捕捉的值,因为是一种拷贝 auto func7 = [=]()mutable { a++; b++; c++; d++; return a + b + c + d; }; cout << func7() << endl; cout << a << " " << b << " " << c << " " << d << endl; // 虽然我们可以自己写仿函数,但是用lambda更方便,编译器可以帮助我们生成,与范围for类似 return 0; }struct Goods { string _name; // 名字 double _price; // 价格 int _evaluate; // 评价 // ... Goods(const char* str, double price, int evaluate) :_name(str) , _price(price) , _evaluate(evaluate) { } }; struct ComparePriceLess { bool operator()(const Goods& gl, const Goods& gr) { return gl._price < gr._price; } }; struct ComparePriceGreater { bool operator()(const Goods& gl, const Goods& gr) { return gl._price > gr._price; } }; int main() { vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } }; // 类似这样的场景,我们实现仿函数对象或者函数指针支持商品中 // 不同项的比较,相对还是比较麻烦的,那么这里lambda就很好用了 sort(v.begin(), v.end(), ComparePriceLess()); sort(v.begin(), v.end(), ComparePriceGreater()); // 使用lambda;lambda是一个对象 // 传给auto /*auto priceLess = [](const Goods& gl, const Goods& gr) { return gl._price < gr._price; }; sort(v.begin(), v.end(), priceLess);*/ // 直接传对象,更方便(传给模板) sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) { return gl._price < gr._price; }); sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) { return gl._price > gr._price; }); sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) { return gl._evaluate < gr._evaluate; }); sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) { return gl._evaluate > gr._evaluate; }); return 0; }// lambda的原理 class lambda8 { public: lambda8(int a_, int& b_) :a(a_) , b(b_) { } int operator()(int x) { ++b; return a + b + x; } private: const int a; int& b; }; auto func8 = [a, &b](int x) { ++b; return a + b + x; }; // 等价于: //lambda8 func8(a, b); //func8(1);通过汇编代码观察:
r1(10000, 2); 00D8297D push 2 00D8297F sub esp,8 00D82982 movsd xmm0,mmword ptr [__real@40c3880000000000 (0D89B50h)] 00D8298A movsd mmword ptr [esp],xmm0 00D8298F lea ecx,[r1] 00D82992 call Rate::operator() (0D81212h) // 汇编层可以看到r2 lambda对象调用本质还是调用operator(),类型是lambda_1,这个类型名 // 的规则是编译器自己定制的,保证不同的lambda不冲突 r2(10000, 2); 00D82999 push 2 00D8299B sub esp,8 00D8299E movsd xmm0,mmword ptr [__real@40c3880000000000 (0D89B50h)] 00D829A6 movsd mmword ptr [esp],xmm0 00D829AB lea ecx,[r2] 00D829AE call `main'::`2'::<lambda_1>::operator() (0D824C0h)std::function是一个“万能容器”:它可以存储任何“可调用对象”(函数、Lambda、函数对象、成员函数等)。
template <class T> class function; // undefined template <class Ret, class... Args> class function<Ret(Args...)>;int f(int a, int b) { return a + b; } struct Functor { public: int operator() (int a, int b) { return a + b; } }; class Plus { public: Plus(int n = 10) :_n(n) { } static int plusi(int a, int b) { return a + b; } double plusd(double a, double b) { return (a + b) * _n; } private: int _n; }; int main() { // 包装各种可调用对象 // 类型擦除 // 包装函数指针,仿函数,lambda function<int(int, int)> f1 = f; function<int(int, int)> f2 = Functor(); function<int(int, int)> f3 = [](int a, int b) {return a + b; }; cout << f1(1, 1) << endl; cout << f2(1, 1) << endl; cout << f3(1, 1) << endl; vector<function<int(int, int)>> v; v.push_back(f); v.push_back(Functor()); v.push_back([](int a, int b) {return a + b; }); for (auto& f : v) { cout << f(1, 1) << endl; } // 包装成员函数的指针 // 静态成员 //function<int(int, int)> f4 = Plus::plusi; function<int(int, int)> f4 = &Plus::plusi; // 取地址最好还是加上 cout << f4(1, 1) << endl; // 调用方面 // 非静态成员(注意:还有一个this指针) function<double(Plus*, double, double)> f5 = &Plus::plusd; Plus ps; cout << f5(&ps, 1.1, 1.1) << endl; // 调用 // 其他写法 function<double(Plus, double, double)> f6 = &Plus::plusd; cout << f6(ps, 1.1, 1.1) << endl; function<double(Plus, double, double)> f7 = &Plus::plusd; cout << f7(Plus(), 1.1, 1.1) << endl; function<double(Plus&&, double, double)> f8 = &Plus::plusd; cout << f8(Plus(), 1.1, 1.1) << endl; // 右值引用,这里可以传匿名对象 // 为什么上面即可以传对象的指针也可以传对象? // 成员函数的指针 auto pf1 = &Plus::plusd; //cout << pf1(&ps, 1.1, 1.1); // 不能这样调用:因为不能显示的传递this指针 cout << (ps.*pf1)(1.1, 1.1) << endl; // 对象的指针 Plus* ptr = &ps; cout << (ptr->*pf1)(1.1, 1.1) << endl; return 0; }#include <iostream> #include <functional> // 1. 普通函数 int add(int a, int b) { return a + b; } // 2. 仿函数 (Functor) struct Subtract { int operator()(int a, int b) { return a - b; } }; // 3. 类成员函数 class Calculator { public: int multiply(int a, int b) { return a * b; } static int divide(int a, int b) { return a / b; } }; int main() { // 声明一个能接受两个 int 并返回 int 的 function std::function<int(int, int)> op; // A. 包装普通函数 op = add; std::cout << "Add: " << op(10, 5) << std::endl; // 输出 15 // B. 包装 Lambda 表达式 op = [](int a, int b) { return a % b; }; std::cout << "Mod: " << op(10, 3) << std::endl; // 输出 1 // C. 包装仿函数 op = Subtract(); std::cout << "Sub: " << op(10, 5) << std::endl; // 输出 5 // D. 包装类静态成员函数 (和普通函数一样) op = Calculator::divide; std::cout << "Div: " << op(10, 5) << std::endl; // 输出 2 // E. 包装类非静态成员函数 (注意!) // 非静态成员函数需要对象实例(隐式的 this 指针) // std::function 的签名需要变更为:<int(Calculator*, int, int)> 或者配合 bind 使用 return 0; }std::bind是一个“适配器”:它可以把一个函数预先固定某些参数,或者改变参数的顺序,生成一个新的可调用对象。
simple(1) template <class Fn, class... Args> /* unspecified */ bind (Fn&& fn, Args&&... args); with return type (2) template <class Ret, class Fn, class... Args> /* unspecified */ bind (Fn&& fn, Args&&... args);#include<functional> using placeholders::_1; using placeholders::_2; using placeholders::_3; int Sub(int a, int b) { return (a - b) * 10; } int SubX(int a, int b, int c) { return (a - b - c) * 10; } class Plus { public: static int plusi(int a, int b) { return a + b; } double plusd(double a, double b) { return a + b; } }; int main() { // bind 本质返回的一个仿函数对象 // 调整参数顺序(不常用) // _1代表第一个实参 // _2代表第二个实参 auto f1 = bind(Sub, _1, _2); auto f2 = bind(Sub, _2, _1); cout << f1(10, 5) << endl; // 50 cout << f2(10, 5) << endl; // -50 // 调整参数个数 // 编译器会根据占位符(_1,_2)来调整Sub的顺序或个数 auto f3 = bind(SubX, 10, _2, _1); // 绑死第一个参数 cout << f2(15, 5) << endl; // 底层operator(),调用SubX,第一个参数10,_1表示第一个实参,_2表示第二个实参 auto f4 = bind(SubX, _1, 10, _2); // 绑死第二个参数 cout << f4(15, 5) << endl; // 底层operator(),调用SubX,参数分别是15,10,5 auto f5 = bind(SubX, _1, _2, 10); // 绑死第三个参数 cout << f5(15, 5) << endl; // 底层operator(),调用SubX,参数分别是15,5,10 // bind作用 function<double(Plus, double, double)> f7 = &Plus::plusd; // 如果要进行多次调用,每次都穿Plus(),比较麻烦;其他参数是变化的 // 绑定通常是这个参数在这一组参数中是固定的,把它绑死 // 绑定返回的是一个可调用对象 cout << f7(Plus(), 1.1, 1.1) << endl; cout << f7(Plus(), 1.1, 2.2) << endl; cout << f7(Plus(), 1.1, 3.3) << endl; function<double(double, double)> f8 = bind(&Plus::plusd, Plus(), _1, _2); cout << f8(1.1, 1.1) << endl; cout << f8(1.1, 2.2) << endl; cout << f8(1.1, 3.3) << endl << endl; // 计算复利的lambda auto func1 = [](double rate, double money, int year)->double { double ret = money; for (int i = 0; i < year; i++) { ret += ret * rate; } return ret - money; }; function<double(double)> func_r1_5_y3 = bind(func1, 0.015, _1, 3); function<double(double)> func_r1_5_y5 = bind(func1, 0.015, _1, 5); function<double(double)> func_r1_5_y20 = bind(func1, 0.015, _1, 20); cout << func_r1_5_y3(100000) << endl; cout << func_r1_5_y5(100000) << endl; cout << func_r1_5_y20(100000) << endl; function<double(double)> func_r10_y3 = bind(func1, 0.1, _1, 3); function<double(double)> func_r10_y5 = bind(func1, 0.1, _1, 5); function<double(double)> func_r10_y20 = bind(func1, 0.1, _1, 20); cout << func_r10_y3(100000) << endl; cout << func_r10_y5(100000) << endl; cout << func_r10_y20(100000) << endl; return 0; }如有不足或改进之处,欢迎大家在评论区积极讨论,后续我也会持续更新C++相关的知识。文章制作不易,如果文章对你有帮助,就点赞收藏关注支持一下作者吧,让我们一起努力,共同进步!