<C++> C++11新的类功能

news2024/12/27 19:55:29

C++11新的类功能

1.默认成员函数

原来C++类中,有6个默认成员函数:

  1. 构造函数
  2. 析构函数
  3. 拷贝构造函数
  4. 拷贝赋值重载
  5. 取地址重载
  6. const取地址重载

最后重要的是前4个,后两个用处不大。默认成员函数就是我们不写编译器会生成一个默认的。

C++11 新增了两个:移动构造函数和移动赋值运算符重载

针对移动构造函数移动赋值运算符重载有一些需要注意的点如下:

  • 如果你没有自己实现移动构造函数,且没有实现析构函数拷贝构造拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝自定义类型成员,则需要看这个成员是否实现移动构造, 如果实现了就调用移动构造没有实现就调用拷贝构造
  • 移动赋值重载同上规则相同
  • 如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

以下代码在vs2013中不能体现,在vs2019下才能演示体现上面的特性。

namespace phw {
    class string {
    public:
        typedef char *iterator;
        iterator begin() {
            return _str;
        }

        iterator end() {
            return _str + _size;
        }

        string(const char *str = "")
            : _size(strlen(str)), _capacity(_size) {
            //cout << "string(char* str)" << endl;

            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }

        // s1.swap(s2)
        void swap(string &s) {
            ::swap(_str, s._str);
            ::swap(_size, s._size);
            ::swap(_capacity, s._capacity);
        }

        // 拷贝构造
        string(const string &s)
            : _str(nullptr) {
            cout << "string(const string& s) -- 深拷贝" << endl;

            string tmp(s._str);
            swap(tmp);
        }

        // 移动构造
        string(string &&s)
            : _str(nullptr) {
            cout << "string(string&& s) -- 移动拷贝" << endl;
            swap(s);
        }

        // 赋值重载
        string &operator=(const string &s) {
            cout << "string& operator=(string s) -- 深拷贝" << endl;
            string tmp(s);
            swap(tmp);

            return *this;
        }

        // s1 = 将亡值
        string &operator=(string &&s) {
            cout << "string& operator=(string&& s) -- 移动赋值" << endl;
            swap(s);

            return *this;
        }

        ~string() {
            //cout << "~string()" << endl;

            delete[] _str;
            _str = nullptr;
        }

        char &operator[](size_t pos) {
            return _str[pos];
        }

        void reserve(size_t n) {
            if (n > _capacity) {
                char *tmp = new char[n + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;

                _capacity = n;
            }
        }

        void push_back(char ch) {
            if (_size >= _capacity) {
                size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
                reserve(newcapacity);
            }

            _str[_size] = ch;
            ++_size;
            _str[_size] = '\0';
        }

        //string operator+=(char ch)
        string &operator+=(char ch) {
            push_back(ch);
            return *this;
        }

        string operator+(char ch) {
            string tmp(*this);
            tmp += ch;
            return tmp;
        }

        const char *c_str() const {
            return _str;
        }

    private:
        char *_str;
        size_t _size;
        size_t _capacity;// 不包含最后做标识的\0
    };

    //const bit::string& to_string(int value)
    phw::string to_string(int value) {
        bool flag = true;
        if (value < 0) {
            flag = false;
            value = 0 - value;
        }

        phw::string str;
        while (value > 0) {
            int x = value % 10;
            value /= 10;

            str += ('0' + x);
        }

        if (flag == false) {
            str += '-';
        }

        std::reverse(str.begin(), str.end());
        return str;
    }
}// namespace phw

// 以下代码在vs2013中不能体现,在vs2019下才能演示体现上面的特性。
class Person {
public:
    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 &&p) = default;
    Person &operator=(Person &&p) = default;

    ~Person() {
        cout << "~Person()" << endl;
    }

private:
    phw::string _name;// 自定义类型
    int _age = 1;     // 内置类型
};

int main() {
    Person s1("张三", 18);
    Person s2 = s1;
    Person s3 = std::move(s1);
    cout << endl;


    return 0;
}

在这里插入图片描述

2.关键字delete

delete关键字用于显式地禁用某些特殊成员函数或运算符,以阻止它们在特定的上下文中被调用或使用。

使用delete关键字,可以在类的声明中删除以下函数:

  1. 删除默认构造函数:

    MyClass() = delete;
    

    这将禁用默认构造函数,阻止对象的无参创建。

  2. 删除复制构造函数和复制赋值运算符:

    MyClass(const MyClass&) = delete;
    MyClass& operator=(const MyClass&) = delete;
    

    这将阻止对象的复制,即禁止使用拷贝构造函数和复制赋值运算符进行对象的复制。

  3. 删除移动构造函数和移动赋值运算符:

    MyClass(MyClass&&) = delete;
    MyClass& operator=(MyClass&&) = delete;
    

    这将阻止对象的移动语义,即禁止使用移动构造函数和移动赋值运算符进行对象的移动操作。

  4. 删除析构函数:

    ~MyClass() = delete;
    

    这将阻止对象的销毁,即禁止调用析构函数进行对象的内存释放。

通过使用delete关键字,可以在编译期间捕捉到一些潜在的错误或不正确的使用。例如,如果尝试复制或移动被删除的函数,编译器将会产生错误。

示例:

class MySingleton {
private:
    MySingleton() = delete;  // 默认构造函数被删除
    MySingleton(const MySingleton&) = delete;  // 复制构造函数被删除
    MySingleton& operator=(const MySingleton&) = delete;  // 复制赋值运算符被删除

public:
    static MySingleton& getInstance() {
        static MySingleton instance;
        return instance;
    }

    void doSomething() {
        // 执行操作
    }
};

int main() {
    MySingleton& singleton = MySingleton::getInstance();
    singleton.doSomething();

    // 错误示例,尝试创建被删除的默认构造函数的对象
    // MySingleton singleton2;  // 编译错误

    return 0;
}

在上面的示例中,通过删除默认构造函数、复制构造函数和复制赋值运算符,实现了一个单例模式的类。这样,阻止了通过复制或拷贝方式创建多个实例。任何尝试复制的操作都会在编译时被捕获并产生错误。

总结来说,C++11的delete关键字为开发者提供了更大的灵活性,可以显式地删除某些函数,以避免在特定情况下的误用和错误。这是C++中一个强大的特性,有助于更好地控制类的行为和语义。

3.final与override

在C++11标准中,关键字finaloverride用于类的继承和虚函数的重写。它们提供了一种显式的方法来控制和标记继承关系和函数重写。

3.1 final

final关键字用于修饰类、虚函数或成员函数,表示它们不能被继承或重写。具体来说:

  • 当应用于类时,final关键字表示该类不能被其他类继承。
  • 当应用于虚函数时,final关键字表示该虚函数不能被派生类重写。
  • 当应用于成员函数时,final关键字表示该成员函数不能在派生类中被重写。

以下是使用final关键字的示例:

class Base final {
    // ...
};

class Derived : public Base {  // 错误,无法继承被标记为final的类
    // ...
};

class Base {
public:
    virtual void foo() const final;
};

class Derived : public Base {
public:
    void foo() const override;  // 错误,无法重写被标记为final的虚函数
};

class Base {
public:
    virtual void foo() const;
};

class Derived : public Base {
public:
    void foo() const final;  // 错误,无法在派生类中重写被标记为final的成员函数
};

3.2 override

override关键字用于显式地标记派生类中的成员函数,以表明它们是基类中虚函数的重写版本。使用override关键字可以增强代码的可读性和可维护性,并帮助编译器检测错误。如果派生类中的函数声明使用了override关键字,但却没有重写基类中的虚函数,则会导致编译错误。

以下是使用override关键字的示例:

class Base {
public:
    virtual void foo() const{}
};

class Derived : public Base {
public:
    void foo() const override{}  // 表示该函数是基类虚函数的重写版本
};

class Base {
public:
    virtual void foo() const{}
};

class Derived : public Base {
public:
    void foo() const{}  // 错误,没有使用override关键字重写基类的虚函数,编译器不会报错
};

override关键字的示例:

class Base {
public:
    virtual void foo() const{}
};

class Derived : public Base {
public:
    void foo() const override{}  // 表示该函数是基类虚函数的重写版本
};

class Base {
public:
    virtual void foo() const{}
};

class Derived : public Base {
public:
    void foo() const{}  // 错误,没有使用override关键字重写基类的虚函数,编译器不会报错
};

注意,在C++11之前,虚函数的重写是隐式的,不需要使用override关键字。但是,使用override关键字可以提供更明确的语义和更好的编译时错误检测。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/672952.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Uniapp 开发 ①(快速上手)

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; 微信小程序 &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f4…

Vue3在工作中使用的一些经验总结

1、隐藏el-tab-pane 设置隐藏 2、Vue中ref的使用 3、Vue中的api 4、component: () &#xff1e; import(‘/views/order/orderDetail‘), 5、ids selections.map((i) > i.ruleId); 6、路由配置的三种方式 项目中使用到的 7、Vue3新特性 8、template在Vue中的作用 9、…

电脑装机后使用Administrator作为电脑账号

目录标题 1 搜索cmd使用管理员权限运行&#xff08;因为直接winr无法用权限打开&#xff09;2 输入net user administrator /active:yes&#xff0c;之后系统会提示命令完成&#xff0c;通过这个指令就是让系统默认账户administrator成为超级管理员&#xff0c;方便接下来的操作…

学习mysql

Mysql SQL语言的规则与规范SQL大小写规范注释数据导入指令 基本的SELECT语句SELECT.列的别名去掉重复行空值参与运算着重号(当有表名是关键字时)显示表结构where 运算符算术运算符 比较运算符号性运算符非符号形运算符空运算符非空运算符最小值运算符最大值运算符BETWEEN AND运…

python处理Excel Pandas xlwings numpy, jupyter,docx,jieba 词频统计 flash

# 批量创建Excel import xlwings # xw.App(visibleTrue,add_bookTrue) 会打开Excel&#xff0c;且不会自动关闭 # xw.App(visibleTrue,add_bookTrue) 会打开Excel&#xff0c;但一晃就自动关闭了 app xlwings.App(visibleTrue, add_bookFalse) for language in [Java, Pyt…

C++——set/multiset再理解

目录 1. 关联式容器 2. 键值对 3. 树形结构的关联式容器 4. set容器 4.1 set的介绍 4.2 set的使用 5. multiset 5.1 multiset的介绍 5.2 mutiset的使用 1. 关联式容器 先前我们已经接触过STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque、forward_…

边缘计算技术主要有哪几种?如何应用在实际场景中?

边缘计算是一种新的计算架构&#xff0c;它将计算资源移动到靠近终端用户的边缘设备中&#xff0c;以实现更快、更可靠、更安全的数据传输和处理。边缘AI智能则是指将人工智能算法和模型部署到边缘设备上&#xff0c;使其能够在设备本身上执行计算和决策&#xff0c;而不需要发…

【unity每日一记】资源和场景加载图文详解

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

Jmeter(一) - 从入门到精通 - 环境搭建(详解教程)

1.JMeter 介绍 Apache JMeter是100%纯JAVA桌面应用程序&#xff0c;被设计为用于测试客户端/服务端结构的软件(例如web应用程序)。它可以用来测试静态和动态资源的性能&#xff0c;例如&#xff1a;静态文件&#xff0c;Java Servlet,CGI Scripts,Java Object,数据库和FTP服务器…

Netty的零拷贝

技术主题 netty本质上就是一款优秀的网络编程框架&#xff0c;凭借自己基于NIO编程&#xff0c;零拷贝等技术细节&#xff0c; 技术原理 零拷贝机制&#xff08;zero-copy&#xff09;是在操作数据时不需要将数据从一块内存复制到另一块内存区域的技术&#xff0c;这样就避免…

Docker学习笔记1

PaaS&#xff1a; 一、虚拟化分类&#xff1a; 虚拟化资源提供者&#xff1a; 1&#xff09;硬件平台虚拟化 2&#xff09;操作系统虚拟化 虚拟化实现方式&#xff1a; type I: 半虚拟化 type II&#xff1a;硬件辅助全虚拟化 type III&#xff1a; 软件全虚拟化&#xff1a; …

【编译、链接、装载十】可执行文件的装载与进程

【编译、链接、装载十】可执行文件的装载与进程 一、进程虚拟地址空间1、demo 二、装载的方式1、分页&#xff08;Paging&#xff09;2、 页映射 三、从操作系统角度看可执行文件的装载1、进程的建立2、页错误 四、进程虚存空间分布1、ELF文件链接视图和执行视图2、堆和栈 一、…

mdk下堆栈地址相关的知识梳理

mdk中&#xff0c;堆栈地址范围不像在gcc工程中那么容易看出来。过程被mdk隐藏了&#xff0c;单纯从代码层面不好看出来。但是基本的流程是这样的&#xff1a;先确定代码其他部分使用RAM的情况&#xff0c;然后紧跟着已使用的RAM地址&#xff0c;在剩下的RAM地址中分配Stack_Si…

2023 年6月开发者调查统计结果——最流行的技术(1)

2023 年6月开发者调查统计结果——最流行的技术&#xff08;1&#xff09; 本文目录&#xff1a; 一、编程、脚本和标记语言 二、数据库 三、云平台 四、网络框架和技术 五、其他框架和库 六、其他工具 七、集成开发环境 八、异步工具 九、同步工具 ​十、操作系统 …

如何在医药行业运用IPD?

医药是关于人类同疾病作斗争和增进健康的科学。它的对象是社会的人。因此&#xff0c;医学与社会科学、医学伦理学具有密切关系。广义的医药行业分为医药工业、医药商业和医疗服务业三大组成部分&#xff0c;其中医药工业包括化学药制剂、原料药、中药饮片、中成药、生物药品、…

chatgpt赋能python:Python有宏定义吗?深入探究

Python有宏定义吗&#xff1f;深入探究 Python语言的高效性以及方便编程的语法&#xff0c;使其成为众多程序员的首选语言。而在编写代码的过程中&#xff0c;宏定义是一个非常有用的编程工具&#xff0c;可以帮助程序员简化代码、提高代码的可读性和可维护性。那么&#xff0…

chatgpt赋能python:Python构造器重载-介绍、实践与准则

Python构造器重载 - 介绍、实践与准则 Python是一种动态强类型编程语言,它支持基于对象的编程范例&#xff0c;这意味着对象被认为是Pyhon编程中的核心概念&#xff0c;同时Python在该领域也有广泛的应用。对于任何一个对象类型&#xff0c;一个类至少需要有一个构造器——它是…

【架构】业务中台应用架构

文章目录 一、什么是业务中台二、为什么需要业务中台三、对于业务中台的认知3.1、微服务不是业务中台3.2、业务中台不是前台应用3.3、业务中台是通用业务机制的实现 一、什么是业务中台 业务中台是以业务领域划分边界&#xff0c;形成高内聚、低耦合的面向业务领域的能力中心&…

SpringCloudAlibaba之Nacos安装指南

SpringCloudAlibaba之Nacos安装指南 文章目录 SpringCloudAlibaba之Nacos安装指南1.Windows安装1.1.下载安装包1.2.解压1.3.端口配置1.4.启动1.5.访问1.6.报错 2.Linux安装2.1.安装JDK2.2.上传安装包2.3.解压2.4.端口配置2.5.启动、关闭 3.Nacos的依赖 1.Windows安装 开发阶段…

STM32G0+EMW3080+阿里云飞燕平台实现单片机WiFi智能联网功能(二)阿里云飞燕平台环境配置

项目描述&#xff1a;该系列记录了STM32G0EMW3080实现单片机智能联网功能项目的从零开始一步步的实现过程&#xff1b;硬件环境&#xff1a;单片机为STM32G030C8T6&#xff1b;物联网模块为EMW3080V2-P&#xff1b;网联网模块的开发板为MXKit开发套件&#xff0c;具体型号为XCH…