[c++] c++ 中的一些关键字:explicit, delete, default, override, final, noexcept

news2024/9/25 11:16:51

1 explicit

explicit 的意思是清楚的,明显的。一般用在类的构造函数中,防止隐式转换。

explicit specifier - cppreference.com

如下代码,

(1) 类 A 的两个构造函数都没有使用 explicit 修饰,所以如下两行代码,隐式转换,是允许的  

A a1 = 1;
A a4 = {4, 5};

(2) 类 B 的两个构造函数都使用 explicit 修饰了,不允许隐式构造,所以下边两行代码编译不通过

B b1 = 1;
B b4 = {4, 5};

(3) 类 B,如下代码,使用强制类型转换,是可以的。

B b5 = (B)1;

#include <iostream>
#include <string>

class A
{
public:
    A(int) { }      // converting constructor
    A(int, int) { } // converting constructor (C++11)
};

class B
{
public:
    explicit B(int) { }
    explicit B(int, int) { }
};

int main()
{
    A a1 = 1;      // OK: copy-initialization selects A::A(int)
    A a2(2);       // OK: direct-initialization selects A::A(int)
    A a3 {4, 5};   // OK: direct-list-initialization selects A::A(int, int)
    A a4 = {4, 5}; // OK: copy-list-initialization selects A::A(int, int)
    A a5 = (A)1;   // OK: explicit cast performs static_cast

    // B b1 = 1;      // error: copy-initialization does not consider B::B(int)
    B b2(2);       // OK: direct-initialization selects B::B(int)
    B b3(4, 5);   // OK: direct-list-initialization selects B::B(int, int)
    // B b4 = {4, 5}; // error: copy-list-initialization does not consider B::B(int, int)
    B b5 = (B)1;   // OK: explicit cast performs static_cast
    return 0;
}

2 delete

指定某个函数禁用。

在单例模式中,一个类只允许创建一个对象,同时也不允许这个类进行拷贝构造或者对象之间进行赋值。怎么做到不让类进行拷贝构造,以及不让对象之间进行赋值呢,这个时候就可以使用 delete 来修饰拷贝构造函数和赋值运算符。

如果在代码中使用了禁用的函数,那么编译的时候会报错。

#include <iostream>
#include <mutex>
 
class Test {
public:
  static Test *GetInstance() {
    std::lock_guard<std::mutex> lock(mtx);
    if (instance == nullptr) {
      instance = new Test();
      return instance;
    }
    return instance;
  };
 
  Test(const Test &) = delete;
  Test &operator=(const Test &) = delete;
 
  ~Test() {
    std::cout << "~Test()" << std::endl;
  };
 
  class Recycler {
  public:
    ~Recycler() {
      if (Test::instance) {
        delete Test::instance;
      } else {
        std::cout << "no need to recycle" << std::endl;
      }
    }
  };
  static Recycler recycler;
 
  void Do() {
    std::cout << "Do()" << std::endl;
  }
 
private:
  static Test *instance;
  static std::mutex mtx;
  Test() {
    std::cout << "Test()" << std::endl;
  };
};
 
Test *Test::instance = nullptr;
std::mutex Test::mtx;
Test::Recycler recycler;
 
void TestDo(Test test) {
  test.Do();
}
 
int main() {
  Test *test = Test::GetInstance();
  test->Do();
  return 0;
}

3 default

这个关键字和 c++ 编译器默认生成的函数有关系。如果定义了一个空类,那么 c++ 编译器会默认生成构造函数,析构函数,拷贝构造函数,拷贝赋值运算符,取地址运算符,取值运算符,移动拷贝构造函数,移动赋值运算符。

以构造函数为例,如果我们自己没有定义构造函数,那么编译器会默认生成一个无形参的构造函数;如果我们定义了有形参的构造函数,那么编译器就不会生成默认无形参的构造函数了。而默认的构造函数在某些使用场景下也会用到,这个时候我们就不需要自己定义一个这样的构造函数,而是使用 default 关键字来提醒编译器,虽然我自己写了有参数的构造函数,但是也让编译器生成默认构造函数。

如下代码,如果不将 Test() 声明为 default,那么在 main() 函数中的 Test t1 这行代码便会导致编译错误。

#include <iostream>
#include <string>

class Test {
public:
  Test() = default;
  Test(std::string str) {
    std::cout << "Test(), str = " << str << std::endl;;
  }
};

int main() {
  Test t1;
  Test t2("hello");
  return 0;
}

自己定义的构造函数需要和 default 构造函数形成重载,不能定义一个和 default 构造函数一样的构造函数,这样是不允许的,比如下边的代码。

#include <iostream>
#include <string>

class Test {
public:
  Test() = default;
  Test() {
    std::cout << "Test()" << std::endl;;
  }
};

int main() {
  Test t1;
  return 0;
}

4 override

显式指定,覆写。

(1)override 可以显式的说明函数覆盖了基类中的虚函数,增加了可读性。对于虚函数来说,即使不使用 override 指定,子类也可以覆写基类中的虚函数

(2)对于非虚函数来说,派生类不能覆写父类的同名函数,使用 override 编译时会报错

#include <iostream>
#include <string>

class Base {
public:
  virtual void Do() {
    std::cout << "Base() Do()\n";
  }

  void Do1() {
    std::cout << "Base() Do1()\n";
  }
};

class Derived : public Base {
public:
  virtual void Do() override {
    std::cout << "Derived() Do()\n";
  }

  // 非虚函数,不能使用 override
  // 派生类也无法覆写父类的同名函数
  void Do1() /* override */ {
    std::cout << "Derived() Do1()\n";
  }
};

int main() {
  Base *b = new Derived;
  b->Do();
  b->Do1();
  return 0;
}

5 final

(1)修饰类,说明这个类不能被继承

(2)非虚函数,不能使用 final 来修饰。因为非虚函数,本身就具有 final 的性质,派生类不能覆写基类中的非虚函数

(3)修饰虚函数,派生类中不能覆写

#include <iostream>
#include <string>

class Base {
public:
  virtual void Do1() {
    std::cout << "Base() Do1()\n";
  }

  virtual void Do2() final {
    std::cout << "Base() Do2()\n";
  }
};

class Derived1 final : public Base {
public:
  virtual void Do1() override {
    std::cout << "Derived1() Do1()\n";
  }

  virtual void Do2() {
    std::cout << "Derived1() Do2()\n";
  }
};

class Derived2 : public Derived1 {
public:
  virtual void Do1() {
    std::cout << "Derived2() Do1()\n";
  }

  virtual void Do2() final {
    std::cout << "Derived2() Do2()\n";
  }
};

int main() {
  Base *b1 = new Derived1;
  Base *b2 = new Derived2;
  b1->Do1();
  b2->Do1();
  return 0;
}

编译报错:

6 noexcept

这个函数不会抛异常,当这个函数出现异常的时候不会向上抛,而是进程被 std::terminate 杀掉。

(1)Do1() 使用 noexcept 修饰,那么函数中抛异常的时候,不会抛给上一级函数,会直接被 std::terminate 杀掉

(2)Do2() 使用 noexcept(true) 修饰,作用和直接使用 noexcept 修饰相同,函数内的异常不会抛给上一级函数,会直接被 std::terminate 杀掉

(3)Do3() 没有被 noexcept 修饰,函数中抛出的异常,可以抛给上一级函数

(4)Do4() 被 noexcept(false) 修饰,函数中抛出异常,可以抛给上一级函数

#include <iostream>
#include <string>

void Do1() noexcept {
  throw "Do1 exception";
}

void Do2() noexcept(true) {
  throw "Do2 exception";
}

void Do3() {
  throw "Do3 exception";
}

void Do4() noexcept(false) {
  throw "Do4 exception";
}

int main(int argc, char *argv[]) {
  if (argc != 2) {
    std::cout << "argc is not 2\n";
    return 0;
  }

  printf("argv[1] = %s\n", argv[1]);
  try {
    if (argv[1][0] == '1') {
      std::cout << "call Do1()\n";
      Do1();
    } else if (argv[1][0] == '2') {
      std::cout << "call Do2()\n";
      Do2();
    } else if (argv[1][0] == '3') {
      std::cout << "call Do3()\n";
      Do3();
    } else {
      std::cout << "call Do4()\n";
      Do4();
    }
  } catch (const char *e) {
    std::cout << "exception: " << e << std::endl;
  }
  return 0;
}

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

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

相关文章

ubuntu 如何使用阿里云盘

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

网络学习:IPV6基础配置

目录 一、配置接口的全球单播地址 二、配置接口本地链路地址 三、配置接口任播地址 四、配置接口PMTU 配置静态PMTU&#xff1a; 配置动态PMTU&#xff1a; 五、接口配置IPV6地址示例&#xff1a; 一、配置接口的全球单播地址 全球单播地址类似于IPv4公网地址&#xff0…

postman下载汉化以及使用

【2023全网最牛教程】10分钟快速上手Postman&#xff08;建议收藏&#xff09;_macbook postman打开慢-CSDN博客 Postman 汉化教程&#xff08;小白&#xff09;配置的具体操作_postman怎么设置中文-CSDN博客 上面是两篇参考的博客 postman是一款支持http协议的接口调试与测试…

100道面试必会算法-10-K 个一组翻转链表

100道面试必会算法-10-K 个一组翻转链表 题目描述 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点…

活动图高阶讲解-09

1 00:00:00,000 --> 00:00:04,000 上次的练习不知道大家做了没有 2 00:00:04,000 --> 00:00:07,000 没有做的话赶紧做 3 00:00:07,000 --> 00:00:09,000 把它发过来 4 00:00:09,000 --> 00:00:11,000 接下来&#xff0c;下一个 5 00:00:11,000 --> 00:00:16…

ARM实验 LED流水灯

.text .global _start _start: 使能GPIOE GPIOF的外设时钟 RCC_MP_AHB4ENSETR的第[4][5]设置为1即可使能GPIOE GPIOF时钟 LDR R0,0X50000A28 指定寄存器地址 LDR R1,[R0] 将寄存器原来的数值读取出来&#xff0c;保存到R1中 ORR R1,R1,#(0x3<<4) 将第4位设置为1 S…

开源项目ChatGPT-Next-Web的容器化部署(一)-- 优化Dockerfile

一、背景 最近比较火的无疑是chatgpt了&#xff0c;找到一款开源github项目&#xff0c;在其基础上修改&#xff0c;定制出适合于自身业务的系统。 它是nodejs后端项目&#xff0c;github地址是&#xff1a;https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web&#xff0c;依…

面试算法-87-分隔链表

题目 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 示例 1&#xff1a; 输入&#xff1a;head [1,4,3,2,5,2], x …

(力扣)删除链表的倒数第N个节点 C++

1、题目描述 2、三种方法 &#xff08;1&#xff09;方法一&#xff1a;计算链表长度 创建一个虚拟节点来处理删除头节点的情况通过计算链表的长度确定要删除节点的位置。使用双指针中的一个指针&#xff0c;移动到要删除节点的前一个位置。将指针后面的节点跳过&#xff0c;…

深度学习 线性神经网络(线性回归 从零开始实现)

介绍&#xff1a; 在线性神经网络中&#xff0c;线性回归是一种常见的任务&#xff0c;用于预测一个连续的数值输出。其目标是根据输入特征来拟合一个线性函数&#xff0c;使得预测值与真实值之间的误差最小化。 线性回归的数学表达式为&#xff1a; y w1x1 w2x2 ... wnxn …

openGauss学习笔记-249 openGauss性能调优-使用Plan Hint进行调优-Join顺序的Hint

文章目录 openGauss学习笔记-249 openGauss性能调优-使用Plan Hint进行调优-Join顺序的Hint249.1 功能描述249.2 语法格式249.3 参数说明249.4 示例 openGauss学习笔记-249 openGauss性能调优-使用Plan Hint进行调优-Join顺序的Hint 249.1 功能描述 指明join的顺序&#xff0…

内存卡的照片怎么突然就找不到了,内存卡照片突然找不到如何恢复

最近,我遇到了一个令人困惑的问题,就是我的内存卡中的照片突然间找不到了。作为一个热爱摄影的人,我经常使用内存卡来存储我的珍贵照片。然而,最近我发现,无论我如何搜索和浏览,这些照片似乎就像消失了一样。内存卡照片突然找不到如何恢复?虽然挺沮丧的,但幸好遇上了以…

五分钟快速搭建个人游戏网站(1Panel)

五分钟快速搭建个人游戏网站&#xff08;1Panel&#xff09; 环境要求&#xff1a;主流 Linux 发行版本&#xff08;基于 Debian / RedHat&#xff0c;包括国产操作系统&#xff09;&#xff1b; 如果是Windows OS的可以通过WSL来实现安装。 1 介绍 1Panel 是一个基于 Web 的 L…

OpenCV+OpenCV-Contrib源码编译

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、OpenCV是什么&#xff1f;二、OpenCV 源码编译1.前期准备1.1 源码下载1.2 cmake安装1.3 vscode 安装1.4 git 安装1.5 mingw安装 2.源码编译2.1 打开cmake2.…

[ESP32]:基于HTTP实现百度AI识图

[ESP32]&#xff1a;基于HTTP实现百度AI识图 测试环境&#xff1a; esp32-s3esp idf 5.1 首先&#xff0c;先配置sdk&#xff0c;可以写入到sdkconfig.defaults CONFIG_IDF_TARGET"esp32s3" CONFIG_IDF_TARGET_ESP32S3yCONFIG_PARTITION_TABLE_CUSTOMy CONFIG_PA…

vue.config.js配置项

vue.config.js配置项 vue-cli3 脚手架搭建完成后&#xff0c;项目目录中没有 vue.config.js 文件&#xff0c;需要手动创建 创建vue.config.js vue.config.js(相当于之前的webpack.config.js) 是一个可选的配置文件&#xff0c;如果项目的 (和 package.json 同级的) 根目录中存…

数组不初始化带来的问题及解决、动态分配

C中数组不初始化会输出什么结果 在C中&#xff0c;如果你声明了一个数组但没有对其进行初始化&#xff0c;数组的元素将具有未定义的值。这意味着数组元素的值是不确定的&#xff0c;可能是垃圾值。 当你访问未初始化的数组元素时&#xff0c;可能会得到以下结果&#xff1a;…

力扣---全排列---回溯

思路&#xff1a; 递归做法&#xff0c;一般会有visit数组来判断第 i 位是否被考虑了。我们先考虑第0位&#xff0c;再考虑第1位&#xff0c;再考虑第2位...dfs函数中还是老套路&#xff0c;先判定特殊条件&#xff0c;再从当下的角度&#xff08;决定第 j 位是哪个元素&#x…

Docker 【通过Dockerfile构建镜像】【docker容器与镜像的关系】

文章目录 前言一、前期的准备工作二、上手构建一个简单的镜像三、DcokerFile1 指令总览2 指令详情 四、Dockerfile文件规范五、docker运行build时发生了什么?六、调试手段1. 修改镜像打包后&#xff0c;如何验证新内容已更新至镜像 七、Dockerfile优化方案 前言 docker构建镜…

优化选址问题 | 基于鹈鹕算法求解基站选址问题含Matlab源码

目录 问题代码问题 鹈鹕算法(Pelican Optimization Algorithm, POA)是一种相对较新的启发式优化算法,模拟了鹈鹕鸟觅食的行为。这种算法通常用于解决复杂的优化问题,如函数优化、路径规划、调度问题等。基站选址问题通常是一个复杂的优化问题,需要考虑覆盖范围、干扰、成…