• 特殊类与类型转换


    目录

    一、特殊类设计

    二、类型转换


    一、特殊类设计

    只能在堆上创建对象

    首先需要将其构造函数设为私有

    其次就是借助静态成员函数来得到对象 

    同时,还需将拷贝构造删掉,否则也可以在栈上创建对象 

    只能在栈上创建对象 

    同上,一样需要将构造函数私有

    然后借助静态成员函数来得到对象 

    如果new时初始化,即有拷贝构造,那一样可以在堆上创建对象,但这里不能将拷贝构造删掉,否则就无法得到对象,因为上图函数匿名对象时,也需要拷贝构造 

    所以这里需要将new屏蔽掉

    不能被拷贝 

    C++98

    将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有
    C++11
    直接在后面加一个=delete即可
    不能被继承
    C++98
    将构造函数设为私有即可
    C++11
    在类后面加一个final

    单例模式

    概念:一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全 局访问点,该实例被所有程序模块共享

    下面的饿汉模式和懒汉模式都是以统计快速排序递归次数为例

    饿汉模式

    概念:提前准备好,随时可以吃,在main函数之前就创建好了单例对象,程序随时可以访问这个单例对象

    成员变量有3个,一个是该类的静态成员对象,一个用来统计次数,另一个则用来保存每次快速排序分出的区间

    首先需要将构造函数设为私有,以及将拷贝构造给删掉

     

    同时还需定义该类的静态成员对象

    用一个静态成员函数来得到该类的静态成员对象

    下图第一个函数返回次数的值,第二个来对次数增加,第三个则是将区间保存至vector中

     在快速排序中调用上述函数

    测试用例

     

     

     打印调用的次数,该快速排序进行了优化,区间很小时,借助了插入排序,所以次数偏少了一些

    懒汉模式

    概念:事先没有准备好,第一次访问时,才创建单例对象

    和饿汉模式一样,也有3个成员变量,只不过该类对象改为了对象指针

    定义该对象指针

    获取对象 

    除了获取对象有区别外,其余成员函数与饿汉模式一致!

    上述第一次获取对象时会存在线程安全问题,比如t1和t2线程同时进入if语句,t2线程先创建对象返回,然后t2将次数增加,而t1又创建对象,次数就会发生变化,所以会出现线程安全问题 

    解决方式还是加锁

    声明一个锁的成员变量以及定义

    下图这种情况是双检查加锁,外面套一层if语句是为了提高效率,比如t1已经创建好对象了,而t2再来时,就不会再加锁了

    单例对象回收问题

    一般懒汉的单例对象,不需要回收,因为进程正常结束,资源都会还给系统,这个对象只有一个系统自动回收也没什么问题,如果在单例对象释放析构时,有一些要完成的动作,比如要记录日志等等,那就可以定义一个回收类,直接定义在类内部即可,如下图

    在该类中再加一个静态成员变量gc,以及类外定义gc

     

    下图这种写法在C++11中也可以,比较简洁,因为C++11进行了优化,所以static sInst对象构造初始化是线程安全的,但在C++98中多线程调用时,static sInst对象构造初始化并不能保证下线程安全

    对比饿汉模式和懒汉模式

    饿汉模式

    优点:简单

    缺点:

    无法控制创建单例对象初始化顺序,假如两个单例类A和B,要求A单例先创建,B单例后创建,B的创建依赖A;

    如果单例对象初始化很费时间,会导致程序启动慢,就像卡死了一样

    懒汉模式

    优点:

    对应饿汉模式的两个缺点

    缺点

    相对复杂一些,尤其还要控制线程安全的问题 

    二、类型转换

    为什么C++会提出规范类型转换

    因为C++兼容C,也就会保留C的隐士类型转换和强制类型转换,但这往往会导致在程序出现一些问题,如下图,end会提升成无符号整形,所以不可能会小于0,所以C++提出了四种类型转换 

    提示:隐士类型转换:相近类型--意义相似的类型

    static_cast
    static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换,即用于相近类型的转换
    reinterpret_cast
    reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型,如下图,将一个有参数有返回值的函数类型转换成了无参数无返回值的函数类型,非常的BUG,下面转换函数指针的代码是不可移植的,所以不建议这样用
    C++不保证所有的函数指针都被一样的使用,所以这样用有时会产生不确定的结果
    const_cast
    const_cast最常用的用途是删除变量的const属性,方便赋值,如下图,a的const属性被删掉,打印*p变为了3,而打印a依然为2,则是因为const属性被删掉后与编译器的优化冲突,内存存的是3,而a没有从内存去取值,所以造成误判
    解决方式,则是在前面加一个volatile关键字,从而告诉编译器不要去优化,每次去内存取值
    注意:C++单独把这个分出来,是为了提醒用的人注意const的属性删掉后,会被修改。小心和编译器优化冲突误判 
    dynamic_cast
    dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
    向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
    向下转型:父类对象指针/引用- >子类指针/引用(用dynamic_cast转型是安全的)
    如下图,哪怕用reinterpret_cast也不能将子类对象给父类对象

     

     

    如下图,如果pa指向的父类对象,那么则转换不成功,返回nullptr,如果pa指向的子类对象,那么则转换成功,返回对象指针

     

    注意:

    dynamic_cast只能用于含有虚函数的类
    dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
    explicit
    explicit关键字能阻止经过转换构造函数进行的隐式转换的发生​​​​​​​ 
  • 相关阅读:
    石油化工行业中低压电动机回路抗晃电解决方案
    JHOK-ZBG2漏电继电器
    qt 简单实验 一个可以向左侧拖拽缩放的矩形
    DSPE-PEG-FITC Fluorescein-PEG-DSPE 磷脂-聚乙二醇-荧光素可提高溶解度
    微服务13:云基础场景下流量策略实现原理
    Util应用框架Web Api开发环境搭建
    MySQL 存储过程,语法+示例,超详细!!
    词法分析考试做题必备注意点!
    Unity技术手册-UGUI零基础详细教程-ScrollBar和ScrollView
    政策加码聚焦工业现代化发展,团队聚能驱动AI机器视觉高质量发展
  • 原文地址:https://blog.csdn.net/weixin_58867976/article/details/126138288