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

news2024/11/18 21:25:27

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/670128.html

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

相关文章

大家知道什么是CDN吗?对网站有什么帮助?

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言什么是CDN&#xf…

【Python 随练】自由落体运动

题目&#xff1a; 一球从 100 米高度自由落下&#xff0c;每次落地后反跳回原高度的一半&#xff1b;再落下&#xff0c;求它在第 10 次落地时&#xff0c;共经过多少米&#xff1f;第 10 次反弹多高&#xff1f; 简介&#xff1a; 在本篇博客中&#xff0c;我们将解决一个物…

华为OD机试之阿里巴巴找黄金宝箱(IV)(Java源码)

阿里巴巴找黄金宝箱(IV) 题目描述 一贫如洗的樵夫阿里巴巴在去砍柴的路上&#xff0c;无意中发现了强盗集团的藏宝地&#xff0c;藏宝地有编号从0-N的箱子&#xff0c;每个箱子上面有一个数字&#xff0c;箱子排列成一个环&#xff0c;编号最大的箱子的下一个是编号为0的箱子。…

[进阶]网络通信:概述、IP地址、InetAddress

什么是网络编程&#xff1f; 可以让设备中的程序与网络上其他设备中的程序进行数据交互&#xff08;实现网络通信的&#xff09;。 Java提供的网络编程解决方案就是在java.net.*包下进行网络编程。 基本的通信架构 基本的通信架构有2种形式&#xff1a;CS架构&#xff08;Cl…

C++IO流和类型处理(11)

IO流 IO流包括 标准IO流&#xff0c;字符串流&#xff0c;文件流 标准IO流 基础使用 #include <iostream> //包括istream和ostream cin >> ----- 标准输入 cout<< ----- 标准输出 clog<< ----- 带缓冲区的标准错误 cerr<< ----- 不带缓冲…

lazada、速卖通、煤炉、eBay 、亚马逊测评环境系统:如何掌握核心养号技巧?

作为一个准备跨足测评行业的业者&#xff0c;或是一个正在考虑将电商业务转向测评服务的卖家&#xff0c;一份详尽的养号指南绝对是你不可错过的知识宝库。 跨境电商平台无疑是巨大的数据中心&#xff0c;它们不仅检测你的设备参数和IP&#xff0c;还分析你的购物习惯&#xf…

mapbox-gl 点位编辑功能

文章目录 前言方式一&#xff1a;借助 Marker添加自定义icon添加POI图层&#xff0c;绑定对应事件基于Marker交互创建自定义Marker编辑 / 创建POI 方式二&#xff1a;采用 mapbox-gl-draw 插件总结 前言 矢量在线编辑是gis常用的编辑功能&#xff0c;兴趣点&#xff08;POI&am…

力扣算法练习(一)

目录 1. 两数相加&#xff08;2&#xff09; 2. 寻找两个正序数组的中位数&#xff08;4&#xff09; 1. 两数相加&#xff08;2&#xff09; 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储…

MySQL 中的常用函数详解

0️⃣前言 MySQL是一种常用的关系型数据库管理系统&#xff0c;它提供了许多内置函数来处理数据。本文将介绍MySQL中的各种常用函数&#xff0c;包括字符串函数、日期函数、数学函数、聚合函数等。 文章目录 0️⃣前言1️⃣字符串函数1.1CONCAT函数1.2SUBSTRING函数1.3REPLACE函…

高级SQL语句1

高级SQL语句 建立实验环境高级语句1.---- SELECT ----显示表格中一个或数个字段的所有数据记录2.---- DISTINCT ----不显示重复的数据记录3.---- WHERE ----有条件查询4.---- AND OR ----且 或 &#xff08;一般配合where使用&#xff09;5.---- IN ----显示已知的值的数据记录…

私家云二代/比特米盒安装Armbian Blueseye到Emmc

快捷导航 私家云二代/比特米盒安装Armbian Blueseye到Emmc设备介绍前期准备硬件清单Windows电脑一台Type-C数据线一根U盘或SD卡一个键盘一把显示器HDMI数据线 软件清单Amlogic USB Burning ToolUSB烧录工具SSH工具 下载清单Amlogic刷机工具USB烧录工具ATV6.imgDTB文件BIN文件切…

Spring Security OAuth2授权原理、流程与源码解读

文章目录 前言AuthorizationServerConfigurerAdapter(身份认证服务配置适配器)OAuth2AuthorizationServerConfiguration(OAuth2授权服务配置) EnableAuthorizationServer(开启身份认证服务)AuthorizationServerEndpointsConfigurations身份认证服务站点配置类AuthorizationEndp…

HITSZ嵌入式计算(研)23年Keil模拟器项目解决方案

HITSZ嵌入式计算&#xff08;研&#xff09;23年Keil模拟器项目解决方案 1. 项目介绍2. Keil安装3. 创建新项目3.1 参考博文3.2 流程 4. 发送串口数据4.1 参考博文4.2 串口收发流程 5. 产生波形5.1 头文件封装5.2 初始化GPIO口5.3 产生并观察方波 6. Keil信号函数和中断6.1 中断…

佩戴舒适的蓝牙耳机有哪些品牌?不伤耳的蓝牙耳机推荐

​真无线蓝牙耳机逐渐成为大家日常必不可少的数码产品&#xff0c;也随着耳机的发展&#xff0c;人们对蓝牙耳机的要求也越来越高&#xff0c;不仅音质要好&#xff0c;长时间佩戴也要舒适&#xff0c;更是能够应用于多种场景中使用&#xff0c;但挑选蓝牙耳机也是一门学问&…

kettle开发-Day38-超好用自定义数据处理组件

目录 前言&#xff1a; 一、半斤八两&#xff0c;都不太行 1、表输入&#xff0c;速度快&#xff0c;但不稳妥 2、稳的一批&#xff0c;但是慢的像蜗牛 二、各诉衷肠&#xff0c;合作共赢 1、表输入&#xff0c;高效数据插入 2、插入更新&#xff0c;一个都不能少 三、表输…

## flink- mysql同步数据至starrocks-2.5.0之数据同步

flink- mysql同步数据至starrocks-2.5.0之数据同步 mysql 创建 表 CREATE TABLE t_user (id bigint NOT NULL AUTO_INCREMENT,user_name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,age int DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB…

手机app测试杂谈

手机上的 app 分为基于 HTML5 的 app(类似于 pc 上的 b/S 应用)和本地 app(类似于 C/S 结构)。 所以测试上我们也可以充分吸收 web 的 b/s 和 c/s 测试经验。但是不同于 pc 上的应用 测试&#xff0c;手机上的测试有其独特性 测试前的思考:我们这个产品主要是做什么的?为什么我…

03. 青龙面板配置B站快速升级任务天选时刻脚本(保姆级图文)

目录 功能介绍与环境要求1. 修改配置文件拉取.sh脚本2. 拉取库脚本3. 安装 dotnet 环境4.1 扫码登录方式4.2 b站cookie方式登录&#xff08;如果你扫码成功了就不用看这个了&#xff09;获取cookie新建cookie的环境变量 5. 配置任务设置变量6. 运行每日任务测试一下总结 欢迎关…

搭建cloud项目以及各个依赖和配置说明

文章目录 背景步骤配置父pom文件spring-cloud和spring-cloud-alibaba的区别 添加网关模块配置网关的application.yml文件网关入口 普通模块普通模块的配置文件&#xff1a;普通模块的pom文件启动类&#xff1a;application.yml文件和bootstrap.yml文件的区别 总结 背景 最近在…

chatgpt赋能python:Python描述符:更加灵活的属性管理方式

Python描述符&#xff1a;更加灵活的属性管理方式 Python是一种高级编程语言&#xff0c;它的简单易用、高效性和灵活性使得它成为了现代企业和开发者的首选开发语言之一。然而&#xff0c;在使用Python编写代码时&#xff0c;很多时候需要对属性进行访问和修改&#xff0c;而…