C++特殊类和类型转换剖析

目录

一、特殊类

1.1拒绝被拷贝的类

1.2 限制在堆上创建类

1.3 限制在栈上创建的类

1.4 不能被继承的类

二、类型转换

2.1 static_cast

2.2 reinterpret_cast

2.3 const_cast

2.4 dynamic_cast


一、特殊类

什么是特殊类?在普通类的设计基础上,提出一些限制条件设计的类就是特殊类。

1.1拒绝被拷贝的类

拷贝只会发生在两个场景中:拷贝构造函数以及赋值运算符重载。
禁止拷贝的类只需要让该类禁止调用拷贝构造函数和赋值运算符重载函数即可。

在C++98中常用如下方式:

class CopyBan
{
public:CopyBan(){}
private:CopyBan(const CopyBan& cb);//拷贝构造函数声明CopyBan& operator=(const CopyBan& cb);//赋值运算符重载声明
};

将拷贝构造函数和赋值运算符重载函数只声明不定义,并且设置成私有。

原因:

  •  只声明不定义:在调用拷贝构造和赋值运算符重载函数的时候,由于没有定义就会产生链接错误,在编译阶段就报错。
  •  设置成私有:防止在类外定义拷贝构造和赋值运算符重载函数,此时即使定义了,因为私有的原因,在类外也无法调用

C++11新方法:

  •  使用C++11中的给delete新赋予的意义来禁止生产拷贝构造和赋值运算符重载函数。

此时编译器也不会自动生成默认的拷贝构造和赋值运算符重载函数。

1.2 限制在堆上创建类

正常创建类对象时,会在栈上创建,并且自动调用构造函数来初始化。

  • 只能在创建在堆上时,就需要让该对象只能通过new来创建,并且调用构造函数来初始化。

定义一个静态成员函数,在该函数内部new一个Heaponly对象。将构造函数和拷贝构造函数私有,并且禁止生成拷贝构造函数。

非静态成员函数在调用的时候,必须使用点(.)操作符来调用,这一步是为了传this指针。

这样的前提是先有一个HeapOnly对象,但是构造函数设置成了私有,就无法创建这样一个对象。

而静态成员函数的调用不用传this指针,也就不用必须有HeapOnly对象,只需要类域::静态成员函数即可。

静态成员函数属于HeapOnly域内,所以在new一个对象的时候,可以调用私有的构造函数。

1.3 限制在栈上创建的类

  • 主要要做到不能在堆上创建类对象。
  • new一个对象的时候,会调用该类的operator new(size_t size)函数,在释放资源的时候又会调用该类的operator delete(void* p)函数。

方法1:

所以防止在堆上创建类对象就是要禁止调用这两个函数。

class StackOnly
{
public://构造函数StackOnly(){}void* operator new(size_t size) = delete;//禁止调用newvoid operator delete(void* p) = delete;//禁止调用delete
};

使用delete来禁止这两个函数的调用,那么在new一个对象的时候,就会产生编译错误,从而无法在堆区上创建类对象。

方法2:

class StackOnly
{
public:static StackOnly CreateObject(){return StackOnly();}
private:StackOnly(){}
};

另一种方式就是和之前一样,通过一个静态成员函数在栈区上创建一个类对象,并且将默认构造函数私有化。

设计特殊类的核心点:只能通过静态成员函数来创建类,封掉其他所有创建方式

1.4 不能被继承的类

C++98方式:

//基类
class NonInherit
{
private://基类构造函数私有NonInherit(){}
};//派生类
class B :public NonInherit
{};
  •  基类的构造函数私有,派生类在创建对象的时候,无法调用基类的构造函数。

C++11添加了 final 关键字

class NonInherit final
{}

二、类型转换

在C语言中,如果赋值运算符(=)两边的类型不同,或者形参和实参类型不匹配,或者返回值类型和接收值类型不一致,就需要发生类型转换。

C语言中有两种类型转换:

  • 隐式类型转换:编译器在编译阶段自动进行,能转就转,不能转就编译失败。
  • 显式类型转换:需要用户自己处理。
int main()
{int i = 1;double d = i;//隐式类型转换printf("%d, %.2f\n", i, d);int* p = &i;int address = (int)p;//显式类型转换printf("%x, %d\n", p, address);return 0;
}

但是C语言的类型转换存在如下缺陷:

  • 隐式类型转换有些情况下会出现问题,比如数据精度发生丢失(整形提升等)。
  • 显式类型转换将所有情况混合在一起,代码不够清晰。

所以C++提出了自己的类型转换风格,但是仍然可以使用C语言的转换风格,因为要兼容C语言。

2.1 static_cast

  • C语言的隐式类型转换在C++中就可以使用static_cast来转换,但是不能用于两个不相关的类型进行转换。
double d = 3.14;
int a = static_cast<int>(d);

static_cast 后的<>里放要转换的类型,()里放被转换的类型。

2.2 reinterpret_cast

  • C语言的显式类型转换在C++中就可以reinterpret_cast,用于将一种类型转换为另一种不同的类型。
int a = 1;
int* pa = &a;
int address = reinterpret_cast<int>(pa);

2.3 const_cast

  • 用在删除变量的const属性,方便赋值。
const int a = 2;
int* p = const_cast<int*>(&a);
*p = 3;
  • const_cast 更多的是一种警示,表示去除了const属性,要谨慎操作。

2.4 dynamic_cast

  • 用于将一个父类对象的指针或者引用转换为子类对象的指针或引用(动态转换)。

向上转换:子类对象的指针或引用 → 父类对象的指针或引用。(不发生类型转换,是语法允许的,发生了切片)
向下转换:父类对象的指针或引用 → 子类对象的指针或引用。(用 dynamic_cast 转换是安全的)

//父类
class A
{
public:virtual void f(){}int _a = 1;
};
//子类
class B : public A
{
public:int _b = 2;
};

在main函数中,传父类指针&ax给函数,在函数中将A* pa父类指针接收该值,然后将其强转为子类指针B*,使用子类指针访问子类成员,bptr->_b = 4发生运行时错误。

        形参A* pa是父类指针,接收的也是父类指针,所以强转成子类指针后访问子类成员_b会发生越界。

解决方法:使用dynamic_cast将父类指针强转为父类指针。

注意:

  • dynamic_cast只能用于父类含有虚函数的类。
  • dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回nullptr。
  • dynamic_cast是安全的,直接使用C语言的转换方式是不安全的。

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

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

相关文章

基于Java+vue的音乐网站设计与实现(源码+文档+数据库)

摘 要 在此基础上&#xff0c;提出了一种基于javavue的在线音乐排行榜系统的设计与实现方法。本系统分为两个大的功能&#xff0c;即&#xff1a;前端显示、后端管理。而在前台&#xff0c;则是播放不同的歌曲&#xff0c;让人可以在上面观看不同的歌曲&#xff0c;也可以观看…

CSS学习

CSS学习 1. 什么是css?2.css引入方式2.1 内嵌式2.2 外联式2.3 行内式2.4 引入方式特点 3. 基础选择器3.1 标签选择器3.2 类选择器3.3 id选择器3.4 通配符选择器 4. 文字基本样式4.1 字体样式4.1.1 字体大小4.1.2 字体粗细4.1.3 倾斜4.1.4 字体4.1.5 字体font相关属性连写 4.2 …

地图自定义省市区合并展示数据整合

需求一&#xff1a;将省级地图下的两个市合并成一个区域&#xff0c;中间的分割线隐藏。 1、访问下方地址&#xff0c;搜索并下载省级地图json文件。 地址&#xff1a;https://datav.aliyun.com/portal/school/atlas/area_selector 2、切换到边界生成器&#xff0c;上传刚刚下…

论文降重同义词替换的实践经验与改进建议 快码论文

大家好&#xff0c;今天来聊聊论文降重同义词替换的实践经验与改进建议&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 标题&#xff1a;论文降重同义词替换的实践经验与改…

Datawhale 12月组队学习 leetcode基础 day3 递归

这是一个新的专栏&#xff0c;主要是一些算法的基础&#xff0c;对想要刷leedcode的同学会有一定的帮助&#xff0c;如果在算法学习中遇到了问题&#xff0c;也可以直接评论或者私信博主&#xff0c;一定倾囊相助 进入正题&#xff0c;今天咱们要说的是递归&#xff0c;递归是是…

Qt中槽函数在那个线程执行的探索和思考

信号和槽是Qt的核心机制之一&#xff0c;通过该机制大大简化了开发者的开发难度。信号和槽属于观察者模式&#xff08;本质上是回调函数的应用&#xff09;。是函数就需要考虑其是在那个线程中执行&#xff0c;本文讨论的就是槽函数在那个线程中执行的问题。 目录 1. connect…

大数据存储技术(3)—— HBase分布式数据库

目录 一、HBase简介 &#xff08;一&#xff09;概念 &#xff08;二&#xff09;特点 &#xff08;三&#xff09;HBase架构 二、HBase原理 &#xff08;一&#xff09;读流程 &#xff08;二&#xff09;写流程 &#xff08;三&#xff09;数据 flush 过程 &#xf…

IS-IS原理与配置3

IS-IS原理与配置 • IS-IS&#xff08;Intermediate System to Intermediate System&#xff0c;中间系统到中间系统&#xff09;是ISO &#xff08;International Organization for Standardization&#xff0c;国际标准化组织&#xff09;为它的CLNP &#xff08;ConnectionL…

OSWBB 部署实现

1、OSWatcher (oswbb) 是一个可供用户下载的工具&#xff0c;可以用来抓取操作系统的性能指标。 是一组shell程序&#xff0c;程序中调用: top, vmstat, iostat, mpstat, netstat,and traceroute等os的监控工具 。OSWatcher 的使用是基于 standard licensing terms 并且不需要…

Alibaba分布式事务组件Seata XATCC实战

1. Seata XA模式实战 XA协议最主要的作用是就是定义了RM-TM的交互接口&#xff0c;XA规范除了定义的RM-TM交互的接口(XA Interface)之外&#xff0c;还对两阶段提交协议进行了优化。 1.1 整体机制 在 Seata 定义的分布式事务框架内&#xff0c;利用事务资源&#xff08;数据…

python3GUI--仿win风格天气By:PyQt5

文章目录 一&#xff0e;前言二&#xff0e;展示1.首页-白色1.首页-白色22.首页-黑色3.天气预报视频4.天气资讯-白色5.天气资讯-黑色6.收藏夹-白色7.收藏夹-黑色8.搜索9.mini-白色10.mini-黑色11.光遇天气 三&#xff0e;心得四&#xff0e;总结五&#xff0e;参考 一&#xff…

编译 pywinhook v1.6.2 的环境设置和步骤

准备做一个鼠标事件响应程序。 查了一下相关python的第三方类库&#xff0c;发现有 pyhook。 一、起源 pyhook 1、pyhook是最早的版本 pyhook支持的python版本比较低&#xff0c;代码在 https://sourceforge.net/projects/pyhook/ 2、之后产生了两个并行版本 pyHook3 和 p…

来聊聊Spring的循环依赖

文章目录 首先了解一下什么是循环依赖简述解决循环依赖全过程通过debug了解Spring解决循环依赖全过程Aservice的创建递归来到Bservice的创建然后BService递归回到了getAservice的doGetBean中故事再次回到Aservice填充BService的步骤 总结成流程图为什么二级就能解决循环依赖问题…

【Qt开发流程】之UDP

概述 UDP (User Datagram Protocol)是一种简单的传输层协议。与TCP不同&#xff0c;UDP不提供可靠的数据传输和错误检测机制。UDP主要用于那些对实时性要求较高、对数据传输可靠性要求较低的应用&#xff0c;如音频、视频、实时游戏等。 UDP使用无连接的数据报传输模式。在传…

如何实现订单自动取消

由于Redis具有过期监听的功能&#xff0c;于是就有人拿它来实现订单超时自动关闭的功能&#xff0c;但是这个方案并不完美。今天来聊聊11种实现订单超时自动关闭的方案&#xff0c;总有一种适合你&#xff01;这些方案并没有绝对的好坏之分&#xff0c;只是适用场景的不大相同。…

图的搜索(二):贝尔曼-福特算法、狄克斯特拉算法和A*算法

图的搜索&#xff08;二&#xff09;&#xff1a;贝尔曼-福特算法、狄克斯特拉算法和A*算法 贝尔曼-福特算法 贝尔曼-福特&#xff08;Bellman-Ford&#xff09;算法是一种在图中求解最短路径问题的算法。最短路径问题就是在加权图指定了起点和终点的前提下&#xff0c;寻找从…

Vue3使用了Vite和UnoCSS导致前端项目启动报错:Error:EMFILE:too many open files

一个 Vue3 的项目&#xff0c;用的是 Vite 打包&#xff0c;通过 npm run dev 运行时&#xff0c;遇到了以下错误&#xff08;尤其是引入了 Element-Plus 后&#xff09;&#xff1a; Error: EMFILE: too many open files&#xff0c;后面是具体的文件路径。。甚至到了 node_mo…

5G工业物联网网关,比4G工业网关强在哪里?

​随着5G技术的广泛应用&#xff0c;越来越多的行业开始探索如何利用5G网络提升效率和创新能力。其中&#xff0c;工业物联网领域是受益最大的领域之一。作为连接物联网设备和网络的关键组件&#xff0c;5G工业物联网网关在这个变革中发挥着至关重要的作用。本文将深入探讨5G工…

指针进阶篇

指针的基本概念&#xff1a; 指针是一个变量&#xff0c;对应内存中唯一的一个地址指针在32位平台下的大小是4字节&#xff0c;在64位平台下是8字节指针是有类型的&#xff0c;指针类型决定该指针的步长&#xff0c;即走一步是多长指针运算&#xff1a;指针-指针表示的是两个指…

赛氪为第五届全球校园人工智能算法精英大赛决赛选手保驾护航

12月10日&#xff0c;以“智青春算未来”为主题的2023年第五届全球校园人工智能算法精英大赛全国总决赛在河海大学江宁校区举行。本次大赛由江苏省人工智能学会主办&#xff0c;自9月份启动以来&#xff0c;共吸引了全国近400所高校的3000多支参赛团队参加。经过校赛、省赛选拔…