C++特殊类的设计与类型转换
特殊类的设计与类型转换
- 特殊类的设计
- 请设计一个类,只能在堆上创建对象
- 请设计一个类,只能在栈上创建对象
- 请设计一个类,只能创建一个对象(单例模式)
- C++的类型转换
特殊类的设计
请设计一个类,只能在堆上创建对象
通过new创建的类就是堆上的。
方法一:
#include<iostream>using namespace std;
class HeapOnly
{
public:static HeapOnly* func()//这里如果不用静态就无法创建对象了,也导致这个函数无法被调用{return new HeapOnly;}
private:HeapOnly()//防止随意的创建对象{}HeapOnly(const HeapOnly& a) = delete;//如果不删除拷贝函数创建的对象还是在栈上
};
int main()
{HeapOnly* p1 = HeapOnly::func();//HeapOnly p2(*p1);//这样避免了p2对象创建在栈上return 0;
}
这里主要以封禁构造函数为主,让外部只能通过调用func函数方式去创建对象,func函数的内部是通过new创建的,这里要注意的就是拷贝构造的问题。
赋值重载不用删除,因为需要现有一个对象才能赋值给另一个对象,上面的代码只会创建出堆上的对象。
方法二:
#include<iostream>using namespace std;class HeapOnly
{
public:HeapOnly(){}void Delete(){this->~HeapOnly();}
private:~HeapOnly(){}HeapOnly(const HeapOnly& a) = delete;
};int main()
{HeapOnly* p1 = new HeapOnly;p1->Delete();return 0;
}
封禁析构函数,需要自己手动释放内存。
请设计一个类,只能在栈上创建对象
这里要注意一点,静态区也不行。
方法一:
#include <iostream>
using namespace std;
class NonInherit
{
public:static NonInherit func(){return NonInherit();}void Pintf(){cout << "Pintf" << endl;}
private:NonInherit(){}NonInherit(const NonInherit& p) = delete;
};
int main()
{NonInherit::func().Pintf();//static NonInherit p1 = NonInherit::func();//防止p1创建在静态区上return 0;
}
这里就像匿名对象的感觉,如果不封拷贝构造就会出现注释上的问题。
方法二:
#include <iostream>
using namespace std;
class NonInherit
{
public:static NonInherit func(){return NonInherit();}void Pintf() const{cout << "Pintf" << endl;}
private:NonInherit(){}NonInherit(const NonInherit& p) = delete;
};
int main()
{const NonInherit& p1 = NonInherit::func();//用引用接收p1.Pintf();//然后在使用return 0;
}
请设计一个类,只能创建一个对象(单例模式)
设计模式:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
单例模式:
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
单例模式有两种实现模式:
饿汉模式
就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。
#include<iostream>
#include<map>
#include<string>
using namespace std;
class Singleton
{
public:static Singleton& func(){return _a;//拿到对象本身}void Insert(string str, int salary){arr[str] = salary;}void Printf(){for (auto& e : arr){cout << e.first << ":" << e.second << endl;}}
private:Singleton(){}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;map<string, int> arr;static Singleton _a;
};
Singleton Singleton::_a;//在外部初始化对象,同类对象只会调用一次构造函数int main()
{Singleton::func().Insert("aaa", 111);Singleton&p = Singleton::func();p.Insert("bbb", 222);p.Insert("ccc", 333);p.Insert("ddd", 444);p.Insert("eee", 555);p.Printf();return 0;
}

这个模式缺点:
如果数据量太大,启动就会非常的缓慢。
如果有多个文件一起,都有饿汉模式的代码,他们互相之间有依赖,但是编译器很难控制先初始化谁。
懒汉模式
如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。
#include<iostream>
#include<map>
#include<string>
#include<mutex>
using namespace std;
template<class T>
class Lock
{
public:Lock(T& p)//因为锁不允许拷贝:_p(p){_p.lock();}~Lock(){_p.unlock();}
private:T& _p;//所以这里成员用引用
};
class Singleton
{
public:static Singleton& func(){if (_a == nullptr)//避免每次调用的时候都进行加锁的操作,提高效率{Lock<mutex> p(mex);//用智能指针是为了防止下面的new出现异常导致未解锁//如果不加锁,容易发生内存泄露,开辟多个空间,最终指针只会指向一处空间if (_a == nullptr)//第一次调用创建对象{_a = new Singleton;}}return *_a;}void Insert(string str, int salary){arr[str] = salary;}void Printf(){for (auto& e : arr){cout << e.first << ":" << e.second << endl;}}
private:Singleton(){}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;map<string, int> arr;static Singleton* _a;static mutex mex;//锁
};
Singleton* Singleton::_a = nullptr;//在外部初始化对象,同类对象只会调用一次构造函数
mutex Singleton::mex;//定义锁
int main()
{Singleton::func().Insert("aaa", 111);Singleton& p = Singleton::func();p.Insert("bbb", 222);p.Insert("ccc", 333);p.Insert("ddd", 444);p.Insert("eee", 555);p.Printf();return 0;
}

并且,一般单例对象不用考虑释放,因为一个进程在结束的时候资源会回收给OS。
如果有需要处理的资源,需要在内部定义一个函数去处理某个资源,然后其他资源不用处理:
static void Delete()//手动释放资源
{Lock<mutex> p(mex);if (_a != nullptr){delete _a;_a = nullptr;}
}
假如忘记回收这个资源了呢?
在内部定义一个GC的类,这个类的析构函数内部调用上面的Delete函数。
class GC
{
public:~GC(){if (_a){cout << "~GC()" << endl;Delete();}}
};
然后再外部定义一个全局的GC类的对象,在程序结束的时候就会去调用析构函数。

主要是帮助检查有没有手动释放掉这一出资源。
注意:C++11前是无法保证线程静态的初始化是安全的,C++11之后可以。
也就是说懒汉还有这种写法:
static Singleton& func()
{static Singleton _a;return _a;
}
函数的成员也就不用了静态对象。
C++的类型转换
C语言有两种类型转换,一个是隐式类型转换,另一个是强制类型转换。
#include<iostream>
using namespace std;int main()
{//隐式类型int a = 1;double b = a;//强制类型int c = 10;int* p = &c;int d = (int)p;return 0;
}
C++有四种类型转换,是期望大家能够规范使用的。
为什么C++需要四种类型转换
C风格的转换格式很简单,但是有不少缺点的:
1.隐式类型转化有些情况下可能会出问题:比如数据精度丢失。
2.显式类型转换将所有情况混合在一起,代码不够清晰。
因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格。
static_cast
static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用。
static_cast,但它不能用于两个不相关的类型进行转换。

reinterpret_cast
reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换
为另一种不同的类型。

const_cast
const_cast最常用的用途就是删除变量的const属性,方便赋值。

这里看起来并没有被赋值成功是因为编译器进行了优化,认为const的变量不会被修改,所以这个值一直放在了寄存器中,并没有从内存中获取,数据一直未被更新到寄存器当中。

dynamic_cast
dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
注意:
1.dynamic_cast只能用于父类含有虚函数的类
2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
#include<iostream>
using namespace std;
class A
{
public:virtual void f() {}int a;
};
class B : public A
{
public:int b;
};
void fun(A* pa)
{// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回B* pb = dynamic_cast<B*>(pa);//子类指向父类,访问父类的内容的时候虚表可能会越界产生报错if (pb)//检查是否合法,其实就是拒绝了子类指向父类{pb->a++;pb->b++;cout << "a++ " << "b++" << endl;}
}
int main()
{A a;B b;fun(&a);fun(&b);return 0;
}

注意:
强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是
否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用
域,以减少发生错误的机会。强烈建议:避免使用强制类型转换。
相关文章:
C++特殊类的设计与类型转换
特殊类的设计与类型转换 特殊类的设计请设计一个类,只能在堆上创建对象请设计一个类,只能在栈上创建对象请设计一个类,只能创建一个对象(单例模式) C的类型转换 特殊类的设计 请设计一个类,只能在堆上创建对象 通过new创建的类就…...
如何通过关键词搜索API接口
如果你是一位电商运营者或者是想要进行1688平台产品调研的人员,你可能需要借助API接口来获取你所需要的信息。在这篇文章中,我们将会讨论如何通过关键词搜索API接口获取1688的商品详情。 第一步:获取API接口的授权信息 在使用API接口前&…...
智驾域控新战争打响,谁在抢跑?
智能驾驶域控制器赛道,已经成为了时下最为火热的市场焦点之一。 最近,头部Tier1均胜电子公布了全球首批基于高通Snapdragon Ride第二代芯片平台的智能驾驶域控制器产品nDriveH,在这一赛道中显得格外引人注意。 就在不久之前,均胜…...
Android 13无源码应用去掉无资源ID的按钮
Android Wifionly项目,客户要求去掉谷歌联系人里的 手机联系人按钮 需求分析 无应用源码,只能通过系统侧去修改 首先通过 Android Studio 工具 uiautomatorviewer 获取父控件资源ID chip_group ,然后通过遍历获取子控件去掉目标按钮 --- a/frameworks/base/core/java/andr…...
【SCI征稿】中科院2区(TOP),正刊,SCIEEI双检,进化计算、模糊集和人工神经网络在数据不平衡中应用
【期刊简介】IF:8.0-9.0,JCR1区,中科院2区(TOP) 【检索情况】SCIE&EI 双检,正刊 【数据库收录年份】2004年 【国人占比】22.78%(期刊国际化程度高) 【征稿领域】进化计算、模…...
Android Audio开发——AAudio基础(十五)
AAudio 是一个自 Android O 引入的新的 Android C API。它主要是为需要低延迟的高性能音频应用设计的。应用程序通过直接从流中读取或向流中写入数据来与 AAudio 通信,但它只包含基本的音频输入输出能力。 一、AAudio概述 AAudio 在应用程序和 Android 设备上的音频输入输出之…...
SDK接口远程调试【内网穿透】
文章目录 1.测试环境2.本地配置3. 内网穿透3.1 下载安装cpolar内网穿透3.2 创建隧道 4. 测试公网访问5. 配置固定二级子域名5.1 保留一个二级子域名5.2 配置二级子域名 6. 使用固定二级子域名进行访问 转发自cpolar内网穿透的文章:Java支付宝沙箱环境支付࿰…...
Mybatis学习笔记二
目录 一、MyBatis的各种查询功能1.1 查询一个实体类对象1.2 查询一个List集合1.3 查询单个数据1.4 查询一条数据为map集合1.5 查询多条数据为map集合1.5.1 方法一:1.5.2 方法二: 二、特殊SQL的执行2.1 模糊查询2.2 批量删除2.3 动态设置表名2.4 添加功能…...
大屏数据可视化开源项目
一、DataGear —— 数据可视化项目 官网:DataGear - 开源免费的数据可视化分析平台 DataGear 是一款开源免费的数据可视化分析平台,数据可视化看板。 功能特性: 1、多种数据源,支持运行时接入任意提供 JDBC 驱动的数据库&#…...
面试经典150题:数组/字符串合集
新专栏,预计两个月写完吧,每天下班回来抽空做几道题。会把做题计划顺序记录下来,如果你有缘,刷到这个开篇序列,那就跟着文章去练题吧。初学者可以慢慢来 88. 合并两个有序数组 void merge(vector<int>& nums…...
Java源文件的执行过程
目录 1.JVM 2.字节码 3.Java源文件执行的过程 4.JIT(Just In Time Compilation) 5.AOT(Ahead Of Time Compilation) 6.AOT破坏Java动态性 7.编译型语言与解释型语言 8.Java-编译与解释并存的语言 9.Java和C的相同点与不同…...
10个ai算法常用库java版
今年ChatGPT 火了半年多,热度丝毫没有降下来。深度学习和 NLP 也重新回到了大家的视线中。有一些小伙伴问我,作为一名 Java 开发人员,如何入门人工智能,是时候拿出压箱底的私藏的学习AI的 Java 库来介绍给大家。 这些库和框架为机器学习、深度学习、自然语言处理等提供了广…...
怎么看服务器带宽大小 103.219.179.X
第一种,可以使用网站测速,这种方式比较便捷,但是由于网站测速是测试服务器发送数据包到他网站节点的一个速度情况,有时候节点问题或者服务器做了封包限制可能导致测试不准确的情况。 第二种,可以在IIS上架设一个大一点…...
图形编辑器开发:最基础但却复杂的选择工具
大家好,我是前端西瓜哥。 对于一个图形设计软件,它最基础的工具是什么?选择工具。 但这个选择工具,却是相当的复杂。这次我来和各位,细说细说选择工具的一些弯弯道道。 我正在开发的图形设计工具的: http…...
apk签名-signapk.jar
如果做平台app开发,需要签platform签名,除了通过adroid.bp或者android.mk的方式使用AOSP整个大工程中签名外,还可以直接通过signapk.jar的方式进行签名,效率更高更快捷简便。 首先我们来回顾下AOSP平台签名的办法。 Android.mk 使…...
【100个高大尚求职简历】简历模板+修改教程+行业分类简历模板 (涵盖各种行业) (简历模板+编辑指导+修改教程)
文章目录 1 简历预览2 简历下载 很多人说自己明明投了很多公司的简历,但是都没有得到面试邀请的机会。自己工作履历挺好的,但是为什么投自己感兴趣公司的简历,都没有面试邀请的机会。反而是那些自己没有投递的公司,经常给自己打电…...
Nginx平滑升级版本或添加模块
文章目录 一、Nginx 平滑升级二、升级失败 回滚操作三、遇到问题 一、Nginx 平滑升级 一般有两种情况下需要升级 nginx,一种是确实要升级 nginx 的版本,另一种是要为 nginx 添加新的模块。 Nginx平滑升级其原理简单概括: (1&am…...
高阶复杂网络重建:从时间序列中重建高阶网络
论文链接:https://www.nature.com/articles/s41467-022-30706-9 一、为什么要研究高阶网络? 复杂网络跟我们生活息息相关,例如社交网络的信息传播,疾病的感染扩散和基因调控网络的相互作用等。越来越多的研究突破了传统网络中两…...
Day05 03-MySQL主从-主主原理与搭建详解
文章目录 第十六章 MySQL的系统架构(主从架构)16.1 MySQL集群架构的介绍16.1.1 主从架构介绍16.1.2 主从复制的原理 16.2 MySQL主从复制的实现16.2.1 环境说明16.2.2 主库配置16.2.3 从库配置16.2.4 主从复制测试 16.3 MySQL主主复制的实现16.3.1 主主复…...
STL之vector
目录 vector模拟实现一. vector的基本框架二. 常用方法及实现1.初始化和清理a. 默认构造函数b. 析构函数 2. 迭代器a. beginb. end 3.数据访问a. sizeb. capacityc. operator[]d. frontc. back 4.增删查改操作a. reserveb. resizec. insertd. push_backe. erasef. pop_back 5.构…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
