C++11新的类功能、STL变化、Lambda表达式和包装器详解

5. 新的类功能

5.1 默认的移动构造和移动赋值

C++11在原有6个默认成员函数(构造函数、析构函数、拷贝构造函数、拷贝赋值重载、取地址重载、const取地址重载)基础上,新增了两个默认成员函数:

  1. 默认移动构造函数:如果没有自己实现移动构造函数,且没有实现析构函数、拷贝构造、拷贝赋值重载中的任意一个,编译器会自动生成默认移动构造。

    • 内置类型成员:按字节拷贝
    • 自定义类型成员:如果该成员实现了移动构造就调用移动构造,否则调用拷贝构造
  2. 默认移动赋值重载函数:规则与移动构造类似,如果没有自己实现移动赋值重载,且没有实现析构函数、拷贝构造、拷贝赋值重载中的任意一个,编译器会自动生成默认移动赋值。

class Person {
public:
    Person(const char* name = "", int age = 0)
        : _name(name), _age(age) {}
private:
    bit::string _name;  // 自定义类型
    int _age;           // 内置类型
};

int main() {
    Person s1;
    Person s2 = s1;          // 拷贝构造
    Person s3 = std::move(s1); // 移动构造
    Person s4;
    s4 = std::move(s2);      // 移动赋值
}

5.2 成员变量声明时给缺省值

C++11允许在类定义中直接为成员变量指定缺省值,这些值将用于初始化列表:

class MyClass {
    int x = 10;      // 直接给缺省值
    double y = 3.14;
};

5.3 default和delete

  1. default:显式指示编译器生成默认版本

    Person(Person&& p) = default;  // 显式生成移动构造
    
  2. delete:禁止编译器生成特定函数

    Person(const Person& p) = delete;  // 禁止拷贝构造
    

5.4 final与override

在继承和多态博客中已经讲解

6. STL中的一些变化

C++11为STL引入了多个新容器,其中最重要的是:

  • unordered_map:基于哈希表的无序映射
  • unordered_set:基于哈希表的无序集合

其他新容器包括:

  • array:固定大小数组
  • forward_list:单向链表

STL容器新增的重要接口:

  1. 右值引用和移动语义相关接口:

    • push_back/insert的右值引用版本
    • emplace系列接口
  2. initializer_list版本的构造函数:

    vector<int> v = {1, 2, 3, 4, 5};
    map<string, string> dict = {{"sort", "排序"}, {"string", "字符串"}};
    
  3. 范围for循环

7. Lambda表达式

7.1 基本语法

Lambda表达式格式:[capture-list] (parameters) -> return-type { body }
[捕捉列表] (参数列表) ->返回值类型 {函数体}
省略规则

  • 1、捕捉为空也不能省略
  • 2、参数为空可以省略
  • 3、返回值可以省略,可以通过返回对象自动推导
  • 4、函数体不能省略
auto add = [](int x, int y) -> int { return x + y; };
cout << add(1, 2) << endl;

7.2 捕捉列表

  1. 显式捕捉

    • [x]:值捕捉x
    • [&x]:引用捕捉x
    • [x, &y]:混合捕捉
  2. 隐式捕捉

    • [=]:隐式值捕捉所有使用的变量
    • [&]:隐式引用捕捉所有使用的变量
  3. 混合捕捉

    • [=, &x]:x引用捕捉,其余值捕捉
    • [&, x]:x值捕捉,其余引用捕捉
  4. mutable:允许修改值捕捉的变量,不影响外部变量(了解即可,不常用)

    auto func = [x]() mutable { x++; };
    

7.3 Lambda的应用

Lambda常用于需要传递谓词的场景,如排序:

vector<Goods> v = {{"苹果", 2.1, 5}, {"香蕉", 3, 4}};

// 按价格升序排序
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
    return g1._price < g2._price;
});

// 按评价降序排序
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
    return g1._evaluate > g2._evaluate;
});

7.4 Lambda的原理

Lambda底层被编译器转换为仿函数类:

// Lambda表达式
auto r = [rate](double money, int year) { return money * rate * year; };

// 编译器生成的类似代码
class Lambda_1 {
public:
    Lambda_1(double rate) : _rate(rate) {}
    double operator()(double money, int year) {
        return money * _rate * year;
    }
private:
    double _rate;
};

8. 包装器

8.1 function

std::function是一个通用的函数包装器,可以包装各种可调用对象:

#include <functional>

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

struct Functor {
    int operator()(int a, int b) { return a + b; }
};

int main() {
    // 包装函数指针
    function<int(int, int)> f1 = f;
    
    // 包装仿函数
    function<int(int, int)> f2 = Functor();
    
    // 包装Lambda
    function<int(int, int)> f3 = [](int a, int b) { return a + b; };
    
    // 包装成员函数
    class Plus {
    public:
        static int plusi(int a, int b) { return a + b; }
        double plusd(double a, double b) { return a + b; }
    };
    // 包装静态成员函数 
    // 成员函数要指定类域并且前⾯加&才能获取地址 
    function<int(int, int)> f4 = &Plus::plusi;
    // 包装普通成员函数 
    // 普通成员函数还有⼀个隐含的this指针参数,所以绑定时传对象或者对象的指针过去都可以
    function<double(Plus*, double, double)> f5 = &Plus::plusd;
}

8.2 bind

std::bind用于绑定参数,可以调整参数顺序和数量:

#include <functional>
using namespace std::placeholders;  // 引入_1, _2, _3...

int Sub(int a, int b) { return a - b; }

int main() {
    // 调整参数顺序
    auto sub1 = bind(Sub, _2, _1);  // 第二个参数变为第一个
    cout << sub1(5, 10) << endl;    // 输出5
    
    // 固定部分参数
    auto sub2 = bind(Sub, 100, _1); // 第一个参数固定为100
    cout << sub2(5) << endl;        // 输出95
    
    // 绑定成员函数
    class Plus {
    public:
        double plusd(double a, double b) { return a + b; }
    };
    //绑定后函数调用不用传类对象,更方便
    function<double(double, double)> f = bind(&Plus::plusd, Plus(), _1, _2);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值