【C++】C++11 -- 新功能

这篇具有很好参考价值的文章主要介绍了【C++】C++11 -- 新功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C++11 – 新功能

默认成员函数

在C++11之前一个类有6个默认成员函数,在C++11标准中又新增了两个默认成员函数,分别是移动构造函数和移动赋值函数

默认移动构造和移动赋值生成的条件

  • 移动构造函数的生成条件:没有自己实现移动构造函数,并且没有自己实现析构函数,拷贝构造函数和拷贝赋值函数
  • 移动赋值重载函数的生成条件:没有自己实现移动赋值重载函数,并且没有自己实现析构函数,拷贝构造函数,拷贝赋值函数

也就是说移动构造和移动赋值的生成条件和之前六个默认成员函数不同,并不是不写就会生成默认的。

特别注意,如果我们自己实现了移动构造和移动赋值,就算没有实现拷贝构造和拷贝赋值,先一起也不会生成默认的拷贝构造和拷贝赋值

默认移动构造函数会做什么

  • 默认生成的移动构造函数:对于内置类型的成员可以完成值拷贝(浅拷贝),对于自定义类型的成员,如果该成员实现了移动构造就调用它的移动构造,否则就调用它的拷贝构造
  • 默认生成生成的移动赋值函数:对于内置类型的成员会完成值拷贝(浅拷贝),对于自定义类型成员,如果该成员实现了移动赋值就调用它的移动赋值,否则就调用它的拷贝赋值

验证默认生成的移动构造函数和移动赋值函数所做的工作

要验证默认生成的移动构造和移动赋值所做的工作,这里使用了类一个简化版的string类,其中只编写了几个我们需要的成员函数

//
// Created by 陈李鑫 on 2023/7/16.
//
#ifndef SIMULATION_REALIZATION_STL_CLX_STRING_HPP
#define SIMULATION_REALIZATION_STL_CLX_STRING_HPP

#endif //SIMULATION_REALIZATION_STL_CLX_STRING_HPP

#include <iostream>
#include <algorithm>
#include <utility>
#include <cassert>


class clx_string{
public:
    typedef char* iterator;
    iterator begin() { return _str;}
    iterator end() { return _str + _size; }
    const char* c_str() const { return const_cast<const char*>(_str); };
    void swap(clx_string& s);
    clx_string(const char* str = "");
    clx_string(const clx_string& s);
    clx_string(clx_string&& s);
    ~clx_string();
    clx_string& operator=(const clx_string& s);
    clx_string& operator=(clx_string&& s);
    char& operator[](size_t i);
    void reserve(size_t n);
    void push_back(char ch);
    clx_string& operator+=(char ch);
    static clx_string to_string(int value);
private:
    char* _str;
    size_t _size;
    size_t _capacity;
};

void clx_string::swap(clx_string& s) {
    std::swap(_size, s._size);
    std::swap(_capacity, s._capacity);
    std::swap(_str, s._str);
}

clx_string::clx_string(const char* str) {
    std::cout << "clx_string(const char* str) -- 直接构造" << std::endl;
    _size = strlen(str);
    _capacity = _size;
    _str = new char[_capacity + 1];
    strcpy(_str, str);
}

clx_string::clx_string(clx_string&& s)
    :_size(0), _capacity(0), _str(nullptr)
{
    std::cout << "clx_string::clx_string(clx_string&& s) -- 移动构造" << std::endl;
    swap(s);
}

// 拷贝构造函数 以前的写法
//clx_string::clx_string(const clx_string& s) {
//    _size = strlen(s.c_str());
//    _capacity = _size;
//    _str = new char[_capacity + 1];
//    strcpy(_str, s.c_str());
//}

// 拷贝构造函数 现代写法
clx_string::clx_string(const clx_string& s)
    : _str(nullptr), _size(0), _capacity(0)
{
    std::cout << "clx_string(const clx_string& s) -- 拷贝构造"  << std::endl;
    clx_string tmp(s.c_str());
    swap(tmp);
    std::cout << std::endl;
    std::cout << std::endl;
}

clx_string::~clx_string() {
    _size = 0;
    _capacity = 0;
    delete[] _str;
    _str = nullptr;
}
clx_string& clx_string:: operator=(const clx_string& s) {
    std::cout << "clx_string& clx_string:: operator=(const clx_string& s) -- 赋值函数重载" << std::endl;
    clx_string tmp(s.c_str());
    clx_string::swap(tmp);
    std::cout << std::endl;
    std::cout << std::endl;
    return *this;
}

clx_string& clx_string::operator=(clx_string&& s) {
    std::cout << "clx_string& clx_string::operator=(clx_string&& s) -- 移动赋值重载" << std::endl;
    swap(s);
    return *this;
}



char& clx_string::operator[](size_t i) {
    assert(0 <= i && i < _size);
    return _str[i];
}

void clx_string::reserve(size_t n) {
    if (n > _capacity) {
        char* tmp = new char[n + 1];
        strncpy(tmp, _str, _size + 1);
        if (_str) {
            delete[] _str;
        }
        _str = tmp;
        _capacity = n;
    }
}
void clx_string::push_back(char ch) {
    while (_size >= _capacity) {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
    }
    _str[_size] = ch;
    _str[_size + 1] = 0;
    _size++;
}
clx_string& clx_string::operator+=(char ch) {
    push_back(ch);
    return *this;
}

clx_string clx_string::to_string(int value) {
    clx_string res;
    bool flag = false;
    if (value < 0) {
        flag = true;
        value = -1 * value;
    }
    while (value > 0) {
        char ch = static_cast<char>(value % 10);
        res += ch + '0';
        value /= 10;
    }
    if(flag) res += '-';
    std::reverse(res.begin(), res.end());
    return res;
}

然后再编译一个简单的Person类,Person类中的成员name的类型就是我们模拟实现的string类

class Person{
public:
    explicit Person(const char* name = "", int age = 0)
        :_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;
    }
    
private:
    clx_string _name;   // 姓名
    int _age;           // 年龄
};

虽然Person类当中没有实现移动构造和移动赋值,但是拷贝构造,拷贝赋值,析构函数都实现了,因此Person类不会生成默认的移动构造和移动赋值

void clx_person_test1() {
    Person s1("clx", 21);
    Person s2 = std::move(s1);
}
// 输出
clx_string(const char* str) -- 直接构造
clx_string(const clx_string& s) -- 拷贝构造
clx_string(const char* str) -- 直接构造

可以看到我们已经使用右值取构造s2但是Person类并没有调用默认生成的移动构造函数,因为_name作为自定义类型并没有调用其的移动构造以及移动赋值。这里调用的是Person的拷贝构造函数,其又调用了clx_string类的拷贝构造函数

生成默认移动构造和移动赋值

为了让Person调用默认生成的移动构造函数和移动赋值函数,我们需要将Person类的拷贝构造,拷贝赋值,析构函数都注释掉,再次运行上述代码

clx_string(const char* str) -- 直接构造
clx_string::clx_string(clx_string&& s) -- 移动构造

可以看到Person类默认生成了移动构造函数,其对自己的自定义成员_name调用了自定义成员的移动构造函数_,我们还可以改一下代码看一下默认移动赋值的效果

void clx_person_test1() {
    Person s1("clx", 21);
    Person s2;
    s2 = s1;
}
clx_string(const char* str) -- 直接构造
clx_string(const char* str) -- 直接构造
clx_string& clx_string:: operator=(const clx_string& s) -- 赋值函数重载
clx_string(const char* str) -- 直接构造

类成员变量初始化

默认生成的构造函数,对于其自定义类型的成员会调用其构造函数进行初始化,但并不会对内置类型的成员进行处理。于是对于C++11支持非静态成员变量在声明时初始化赋值,默认生成的构造函数会使用这些缺省值对成员进行初始化

struct student{
    string s = "clx";
    int age = 18;
};

void clx_student_test1() {
    student s;
    cout << s.s << endl;			// clx
    cout << s.age << endl;    // 18
}

注意这里只是声明,是给声明的成员变量一个缺省值。不是定义!不是定义!

强制生成默认函数关键字default

C++11可以让我们更好的控制要使用的默认成员函数,假设某些情况我们需要使用某个默认成员函数,但是因为某些原因导致无法生成这个默认成员函数,就可以使用default这个关键字强制其生成

struct student{
    student(const student& stu)
        : s(stu.s), age(stu.age){}
        
    string s = "clx";
    int age = 18;
};
void clx_student_test2() {
    student s;
}

这样就不行,编译就会报错。因为Person类中编写了拷贝构造函数,导致无法生成默认的构造函数。默认的构造函数生成条件是没有编写任何类型的构造函数,包括拷贝构造函数

struct student{
    student() = default;          // 默认生成构造函数
    student(const student& stu)
        : s(stu.s), age(stu.age){}

    string s = "clx";
    int age = 18;
};

这样我们可以使用default关键字强制生成默认构造函数。

default不仅能生成默认构造,所有默认成员函数都可以用default关键字强制生成,包括移动构造和移动赋值.

class Person{
public:
    explicit Person(const char* name = "", int age = 0)
        :_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(){}
    Person(Person&&) = default;								// 生成默认的移动赋值和拷贝函数
    Person& operator=(Person&&) = default;
private:
    clx_string _name;   // 姓名
    int _age;           // 年龄
};

void clx_person_test1() {
    Person s1("clx", 21);
    Person s2 = move(s1);
}
clx_string(const char* str) -- 直接构造
clx_string::clx_string(clx_string&& s) -- 移动构造

可以看到默认的移动赋值函数是生成了的

禁用生成默认函数的关键字delete

如果我们想要限制某些默认函数生成时,可以通过一下几种方式

  • C++98: 将函数设置成私有,并只声明不实现,这样外部调用该函数就会报错
  • C++11:在该函数的声明后面加上=delete,表示不让编译器生成该函数的默认版本

final and override 关键字

final 修饰的类

final修饰的类被称为最终类,最终类无法被继承

class UnInheritable final {}

Final 修饰虚函数

final修饰的虚函数,表示该虚函数不能再被重写,如果字类继承后重写了该虚函数编译就会报错

Override 修饰虚函数

override修饰的字类虚函数,检查该类是否是由父类继承下来的并且必须重写,如果没有重写就会报错文章来源地址https://www.toymoban.com/news/detail-582632.html

到了这里,关于【C++】C++11 -- 新功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Copilot的11个新功能,你不能错过!

    我的新书 《Android App开发入门与实战》 已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情 微软发布了Copilot,这个东西真是太疯狂了。 如果你不使用它,你就会在2023年落后了。 将Word文档转换为演示文稿。 从文件中快速创建演示文稿。 通过关键幻灯片总结冗长

    2024年02月04日
    浏览(33)
  • Java 20 新功能介绍

    Java 20 共带来 7 个新特性功能 ,其中三个是孵化提案,孵化也就是说尚在征求意见阶段,未来可能会删除此功能。 JEP 描述 分类 429 作用域值(孵化器) Project Loom,Java 开发相关 432 Record 模式匹配(第二次预览) Project Amber,新的语言特性 433 switch 的模式匹配(第四次预览)

    2024年02月03日
    浏览(47)
  • 官宣Windows11十月的Moment 1来了,新功能!附官方ISO镜像(简/繁/英)

    一个月前(2022年9月)微软正式发布了Windows 11的年度大更新——22H2版本(Build 22621.382),过了没几天当月又推出了Build 22621.525的ISO镜像。给人一种特别操之过急的感觉~ 前天微软又向MVS订阅用户推送了10月份的累积更新的ISO镜像,系统版本号Build 22621.674。Windows11也是维持着每

    2024年02月06日
    浏览(36)
  • python一点通:数据处理顶流Pandas 2.0有什么新功能?

    Pandas 2.0及其后续版本的发布引入了各种功能和增强,标志着在使用Pandas进行数据操作和分析方面的显著演进。这里是对一些新功能的深入解析: 可选依赖的安装: 在Pandas 2.0中,通过pip安装pandas时,可以通过指定extras来安装一组可选的依赖项,例如:pip install “pandas[performan

    2024年02月08日
    浏览(30)
  • 数据可视化工具LightningChart .NET正式发布v10.5.1——拥有全新的3D新功能

    LightningChart.NET完全由GPU加速,并且性能经过优化,可用于实时显示海量数据-超过10亿个数据点。 LightningChart包括广泛的2D,高级3D,Polar,Smith,3D饼/甜甜圈,地理地图和GIS图表以及适用于科学,工程,医学,航空,贸易,能源和其他领域的体绘制功能。 LightningChart .NET v10.5.1正

    2024年02月13日
    浏览(30)
  • Midjourney新功能:角色参照指南

    基本概念 角色参照(Character Reference) :这个功能允许用户在不同的图像生成中保持给定参照角色的一致性。 适用模型 :适用于Midjourney V6和Niji6型号。 功能亮点 跨风格一致性 :可以在不同风格(如动漫风、写实风)中保持角色特征一致。 面部、着装、发型调控 :用户可以

    2024年04月10日
    浏览(48)
  • TypeScript 5.1发布,新功能更新

    1:返回类型增加undefined 这里设置了一个别名 fun,当时使用它的时候,我们必须显示返回一个 undefined 。 现在你可以直接设置返回类型: 而不仅限于 void any 。 4.3版本 :❌ 5.1版本 :✅ 2:getter可以设置和 setter 的不相关类型 在之前版本 ,get 返回类型应该为 set 的子类型,如

    2024年02月09日
    浏览(30)
  • SOLIDWORKS 2023新功能揭秘(一):3D CAD功能的十大更新

    SolidWorks 3D CAD  软件拥有设计、模拟、成本估算、可制造性检查、CAM、可持续设计和数据管理等功能,同时还包含适用于钣金,焊件,曲面,模具,产品配置,DFM和CAM的专业工具,支持ECAD/MCAD协作,复杂的零部件库以及高级真实感渲染。更重要的是具有结构和运动分析功能,

    2024年02月05日
    浏览(29)
  • 三星泄露微软 Copilot 新功能:用自然语言操控各种功能

    3 月 11 日消息,微软计划本月晚些时候发布新款 Surface 电脑和适用于 Windows 11 的 Copilot 新功能,但三星似乎等不及了,在其即将推出的 Galaxy Book4 系列产品宣传材料中泄露了一些即将到来的 Copilot 功能。 三星官网上发布的图片证实了此前关于微软正为其人工智能助手 Copilo

    2024年04月09日
    浏览(70)
  • 揭密.NET 8到底有什么新功能

    .NET 8 是微软于2021年8月24日宣布的下一代编程语言和框架,它是 .NET 宇宙的一部分,与 C# (Common Language Infrastructure) 紧密集成。.NET 8 引入了许多新功能,如原生编译、值类型 (Value Types)、结构化并发 (structured concurrency) 和快速数组 (RapidArray)。.NET 8 还支持本机 (native) AOT (Ahead-Of

    2024年02月03日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包