【C++】特殊类设计类型转换
目录
- 💡前言
- 一,特殊类设计
- 1. 请设计一个类,不能被拷贝
- 2. 请设计一个类,只能在堆上创建对象
- 3. 请设计一个类,只能在栈上创建对象
- 4. 请设计一个类,不能被继承
- 5. 请设计一个类,只能创建一个对象(单例模式)
- 5.1 饿汉模式
- 5.2 懒汉模式
- 二,类型转换
- 1. 内置类型之间
- 2. 内置类型和自定义类型之间
- 3. 自定义类型和自定义类型之间
- 三,C++强制类型转换
- 1. static_cast
- 2. reinterpret_cast
- 3. const_cast
- 4. dynamic_cast
💡前言
本篇文章的内容是C++的拓展学习,主要介绍在某些特定场合下的一些特殊类的设计,并且总结了C/C++中的类型转换。
一,特殊类设计
1. 请设计一个类,不能被拷贝
拷贝只会发生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。
(1) C++98的写法
将拷贝构造函数与赋值运算符重载只声明不定义,并且将其声明为私有即可。
class CopyBan
{// ...private:CopyBan(const CopyBan& cb);CopyBan& operator=(const CopyBan& cb);//...
};
原因:
1.设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了。
2.只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。
(2) C++11写法
C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上=delete,表示让编译器删除掉该默认成员函数。
class CopyBan
{// ...CopyBan(const CopyBan& cb)=delete;CopyBan& operator=(const CopyBan& cb)=delete;//...
};
2. 请设计一个类,只能在堆上创建对象
实现方式1:
(1) 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
(2) 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建。
class HeapOnly
{
public:// 只打开唯一的通道在堆上newstatic HeapOnly* CreateObj(){return new HeapOnly;}HeapOnly(const HeapOnly& hp) = delete;HeapOnly operator=(const HeapOnly& hp) = delete;
private:// 构造函数私有化HeapOnly(){}
};int main()
{HeapOnly* hp = HeapOnly::CreateObj();delete hp;return 0;
}
实现方式2:
(1) 将类的析构函数私有,让其他实例化出的对象无法销毁。
(2) 直接在堆上new对象,再提供一个公有的delete函数。
class HeapOnly
{
public:void Destory(){delete this;}private:// 析构函数私有化~HeapOnly(){}
};int main()
{HeapOnly* hp = new HeapOnly;hp->Destory();return 0;
}
3. 请设计一个类,只能在栈上创建对象
实现方式:
同上将构造函数私有化,然后设计静态方法创建对象返回即可。
class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}//StackOnly(const StackOnly& s) = delete;void* operator new(size_t size) = delete;void operator delete(void* p) = delete;
private:StackOnly():_a(0){}
private:int _a;
};int main()
{StackOnly s4 = StackOnly::CreateObj();return 0;
}
4. 请设计一个类,不能被继承
(1) C++98方式
C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承。
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};
(2) C++11方法
final关键字,final修饰类,表示该类不能被继承。
class A final
{// ....
};
5. 请设计一个类,只能创建一个对象(单例模式)
单例:全局只有唯一实例化对象。
5.1 饿汉模式
饿汉模式就是:进入min函数之前创建好对象,需要时直接调用公有函数获取。
class InforMgr
{
public:// 获取对象static InforMgr& GetInstance(){return _ins;}// 这个函数只是用来说明问题void Print(){cout << _ip << endl;cout << _port << endl;}private:InforMgr(const InforMgr& ins) = delete;InforMgr& operator=(const InforMgr& ins) = delete;InforMgr(){cout << "InforMgr()" << endl;}
private:string _ip = "100.02.4";size_t _port = 3;//提前创建一个静态的全局对象static InforMgr _ins;
};//在类外定义
InforMgr InforMgr::_ins;int main()
{InforMgr::GetInstance().Print();return 0;
}
饿汉模式的问题:
(1) 有多个饿汉模式的单例存在,某个对象初始化内容较多(读文件),会导致程序启动慢。
(2) A和B两个饿汉,对象初始化存在依赖关系,要求A先初始化,B在初始化,饿汉无法保证。
5.2 懒汉模式
懒汉模式就是:不是提前创建好对象,而是什么时候需要,什么时候创建。
(1) C++98方式:
class InforMgr
{
public:// 获取对象static InforMgr& GetInstance(){// 第一次调用才new一个单例对象出来if (_pins == nullptr)_pins = new InforMgr;// 后面再调用时就直接返回这个对象return *_pins;}void Print(){cout << _ip << endl;cout << _port << endl;}private:InforMgr(const InforMgr& ins) = delete;InforMgr& operator=(const InforMgr& ins) = delete;InforMgr(){cout << "InforMgr()" << endl;}
private:string _ip = "100.02.4";size_t _port = 3;static InforMgr* _pins;
};// 在类外定义
InforMgr* InforMgr::_pins = nullptr;int main()
{InforMgr::GetInstance().Print();return 0;
}
(2) C++11方式:
class InforMgr
{
public:// 获取对象static InforMgr& GetInstance(){// 局部静态,第一次调用时才创建单例对象// C++11之后static InforMgr ins;return ins;}void Print(){cout << _ip << endl;cout << _port << endl;}private:InforMgr(const InforMgr& ins) = delete;InforMgr& operator=(const InforMgr& ins) = delete;InforMgr(){cout << "InforMgr()" << endl;}
private:string _ip = "100.02.4";size_t _port = 3;static InforMgr* _pins;
};// 在类外定义
InforMgr* InforMgr::_pins = nullptr;int main()
{InforMgr::GetInstance().Print();return 0;
}
懒汉模式的问题:
线程安全的风险
二,类型转换
1. 内置类型之间
隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败。显式类型转化:需要用户自己处理。
1、隐式类型转换:整形之间/整形和浮点数之间
2、显示类型的转换:指针和整形、指针之间
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;
}
2. 内置类型和自定义类型之间
1、内置类型转换为自定义类型 -> 通过构造函数实现。
2、自定义类型转换为内置类型 -> 通过operator 类型实现。
class A
{
public://explicit A(int a)A(int a):_a1(a),_a2(a){}A(int a1, int a2):_a1(a1), _a2(a2){}// ()被仿函数占用了,不能用// operator 类型实现,无返回类型//explicit operator int()operator int(){return _a1 + _a2;}
private:int _a1 = 1;int _a2 = 1;
};int main()
{string s1 = "1111111";A aa1 = 1; // 单参数隐式类型转换//A aa1 = (A)1; // okA aa2 = { 2,2 }; // 多参数隐式类型转换const A& aa3 = { 2,2 };// 自定义->内置int x = (int)aa1;//本质是://int z = aa1.operator int();int x = aa1;int y = aa2;cout << x << endl;cout << y << endl;return 0;
}
3. 自定义类型和自定义类型之间
通过对应法构造函数实现
class A
{
public://explicit A(int a)A(int a):_a1(a), _a2(a){}A(int a1, int a2):_a1(a1), _a2(a2){}int get() const{return _a1 + _a2;}private:int _a1 = 1;int _a2 = 1;
};class B
{
public:B(int b):_b1(b){}// 把A转换成BB(const A& aa):_b1(aa.get()){}private:int _b1 = 1;
};int main()
{A aa1(1);B bb1(2);bb1 = aa1;B& ref1= bb1;const B& ref2 = aa1;return 0;
}
三,C++强制类型转换
标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:static_cast、reinterpret_cast、const_cast、dynamic_cast。
1. static_cast
static_cast 对应隐式类型转换 – 数据的意义没有改变。
int main()
{double d = 12.34;int a = static_cast<int>(d);cout<<a<<endl;return 0;
}
2. reinterpret_cast
reinterpret_cast 对应强制类型转换 – 数据的意义已经发生改变。
int main()
{double d = 12.34;int a = static_cast<int>(d);cout << a << endl; // 12// 对应强制类型转换--数据的意义已经发生改变int* p1 = reinterpret_cast<int*>(a);return 0;
}
3. const_cast
const_cast 对应强制类型转换中有风险的去掉const属性。
void Test ()
{const int a = 2;int* p = const_cast< int*>(&a);*p = 3;cout<< a <<endl; // 2
}
4. dynamic_cast
dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)。
向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)。
向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)。
注意:
(1) dynamic_cast只能用于父类含有虚函数的类。
(2) dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0。
1.没有用 dynamic_cast 时:
class A
{
public:virtual void f() {}int _a = 1;
};class B : public A
{
public:int _b = 2;
};void fun(A* pa)
{// 指向父类转换时是有风险的,后续访问存在越界访问的风险// 指向子类转换时安全B* pb1 = (B*)pa;cout << "pb1:" << pb1 <<endl;cout << "pb1->_a = " << pb1->_a << endl;cout << "pb1->_b = " << pb1->_b << endl; //指向父类时会越界// 下面的代码直接会报错//pb1->_a++;//pb1->_b++;//cout << pb1->_a << endl;//cout << pb1->_b << endl;
}int main()
{A a;B b;fun(&a);fun(&b);return 0;
}

2.使用 dynamic_cast 时:
dynamic_cast 会先检查是否能转换成功,若指向子类对象,就能成功则转换,若指向父类对象,不能转换成功,则返回NULL。
class A
{
public:virtual void f() {}int _a = 1;
};class B : public A
{
public:int _b = 2;
};void fun(A* pa)
{// dynamic_cast会先检查是否能转换成功(指向子类对象),能成功则转换,// (指向父类对象)不能则返回NULLB* pb1 = dynamic_cast<B*>(pa);if (pb1){cout << "pb1:" << pb1 << endl;cout << "pb1->_a = " << pb1->_a << endl;cout << "pb1->_b = " << pb1->_b << endl; cout << endl;pb1->_a++;pb1->_b++;cout << "pb1->_a = " << pb1->_a << endl;cout << "pb1->_b = " << pb1->_b << endl;}else{cout << "转换失败" << endl << endl;}
}int main()
{A a;B b;fun(&a);fun(&b);return 0;
}

相关文章:
【C++】特殊类设计类型转换
目录 💡前言一,特殊类设计1. 请设计一个类,不能被拷贝2. 请设计一个类,只能在堆上创建对象3. 请设计一个类,只能在栈上创建对象4. 请设计一个类,不能被继承5. 请设计一个类,只能创建一个对象(单…...
为git 命令行 设置代理环境变量
http://t.csdnimg.cn/cAxkg 国内需要修改pinoko根目录下gitconfig文件,添加 [http]proxy http://127.0.0.1:1080 [https]proxy https://127.0.0.1:1080或者通过命令行配置: git config --global http.proxy http://127.0.0.1:1080 git config --glo…...
自定义linux某些常见配置
1.当前路径 echo "PS1\u\h:\w\$ " >> /etc/profile source /etc/profile 2.ssh使能 1.开启openssh 2.权限赋予chown root.root /var/empty/ 3.开发板作为server echo "PermitRootLogin yes" >> /etc/ssh/sshd_config 3开机自启动脚本 1.init…...
告别手动操作!KeyMouseGo实现自动化工作流
前言 在这个快节奏的时代,我们每天都在与电脑打交道,重复着那些繁琐而单调的操作;你是否曾想过,能让电脑自己完成这些任务,而你则悠闲地喝着咖啡,享受着生活?今天,就让我们一起揭开一…...
大型语言模型微调 新进展-4篇 论文
1. Brevity is the soul of wit: Pruning long files for code generation 发布时间:2024-06-29链接:https://arxiv.org/abs/2407.00434机构:伦敦大学学院 (UCL) 本研究针对大型语言模型的代码生成任务中的数据清理问题进行了探索。研究发现…...
专业课140+杭电杭州电子科技大学843信号与系统考研经验电子信息与通信工程真题,大纲,参考书。
顺利上岸杭电,由于专业课考的不错140,群里不少同学希望分享一点经验,回头看看这一年考研复习,确实有得有失,总结一下自己的专业课复习经验,希望对大家有帮助,基础课考的没有专业好,而…...
php 中 (0 == ‘abc‘) 为真
https://andi.cn/page/621653.html...
MacOS Anaconda 安装教程及虚拟环境创建
一、下载 Anaconda 1、Anaconda 官网 2、清华大学开源软件镜像站 点 Date 按时间排序,根据自己 Mac 芯片类型下载对应最新版本的。 Intel 芯片的下载 x86_64 版本的Apple m1 芯片的下载 arm64 版本的 二、安装 Anaconda 将安装包下载到本地后,双击安…...
Mac快速配置ADB环境变量
ADB是进行 Androd 开发时很常用的调试工具,Android SDK 中就包含了该工具,所以如果安装了SDK那只需要在环境变量中配置 Android SDK 的路径即可,本文的环境配置也基于这种场景。 如果需要独立下载 ADB 工具,请参考下面网址&#x…...
Kylin的工作原理及使用分享
前言 在当今信息爆炸的时代,企业和研究机构每天都在生成和收集大量的数据。这些数据中蕴藏着巨大的商业价值和研究潜力,但要从中提取出有用的信息却并非易事。传统的数据处理和分析技术在面对如此庞大的数据量时,往往难以提供快速和有效的响…...
python 使用seleniumwire获取响应数据
seleniumwire 是一个在 Selenium WebDriver 基础上扩展的库,它允许你在使用 Selenium 进行网页自动化测试或爬虫时捕获和修改 HTTP 请求和响应。这对于需要分析网页数据或进行更复杂的网络交互的自动化任务特别有用。 以下是如何使用 seleniumwire 来获取响应数据的…...
用C语言实现双向链表
目录 一.双向链表的结构 二. 双向链表的实现 1. 在List.h中结构体的定义和各函数的声明 1.1 结构体(节点)的定义 1.2 各函数的声明 2. 在List.c中各函数的实现 2.1 初始化 LTInit 2.2 尾插 LTPushBack 2.3 打印 LTPrint 2.4 头插 LTPushFron…...
Github 2024-08-10 Rust开源项目日报Top10
根据Github Trendings的统计,今日(2024-08-10统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Python项目1Turbo:下一代前端开发工具链 创建周期:977 天开发语言:Rust协议类型:MIT LicenseStar数量:25308 个Fork数量:1713 …...
深入解析 ESLint 配置:从零到精通
深入解析 ESLint 配置:从零到精通 ESLint 是一个强大的代码检查工具,主要用于识别 JavaScript 和其他支持的语言中的常见编程错误,并强制执行一致的编码风格。自2013年6月由Nicholas C. Zakas创建以来,ESLint 已成为前端开发中不…...
BTC连续拉涨,击碎空头幻想
原创 | 刘教链 隔夜BTC继续拉涨,急破6万刀,“过了黄洋界,险处不须看”,一度逼近63k,目前暂于61-62k区间休整。从8月5日极限插针下探49k,仅仅3天多时间,就连续拉涨到了61k,总涨幅接近…...
【Spring】Sping笔记01
参考学习:b站浪飞yes ---------------------------------------------------- # 一、Spring 引入 **事务实现** java public class EmployeeServiceImpl implements IEmployeeService { public void save(Employee employee){ // 打开资源 /…...
Gridcontrol纵向/横向合并单元格
指定列值相同,纵向合并: this.gridView1.OptionsView.AllowCellMerge true;//启用合并列 // 启用指定合并列事件 this.gridView1.CellMerge new DevExpress.XtraGrid.Views.Grid.CellMergeEventHandler(gridView1_CellMerge);#region 合并指定的列 pri…...
从周杰伦的《青花瓷》三次更名看方文山的国学情怀与工匠精神
《青花瓷》三次更名,方文山的国学情怀与工匠精神 在华语乐坛上,周杰伦与方文山的合作堪称黄金组合,他们的作品不仅引领了流行音乐的潮流,更让传统文化焕发出新的生机。在这其中,《青花瓷》无疑是他们合作的经典之一&a…...
HATS:分层图注意力神经网络用于股票预测
HATS:分层图注意力神经网络用于股票预测 原创 QuantML QuantML 2024年08月09日 19:08 上海 Content 本文提出了一种名为HATS(Hierarchical Graph Attention Network)的分层图注意力网络,用于预测股市动向。HATS通过选择性地聚合…...
【日常记录-MySQL】MySQL设置root用户密码
Author:赵志乾 Date:2024-08-09 Declaration:All Right Reserved!!! 1. 简介 MySQL8.0.30安装后启动,发现root用户尚未设置密码。以下是两种设置root用户密码的方式。 2. 示例 2.1 mysqladmin…...
PCB虚焊/走线断裂/焊盘脱落工程师易漏判
PCB 故障中,30% 并非元件损坏,而是 PCB 本身的隐性故障—— 虚焊、走线断裂、焊盘脱落、过孔开路。这类故障外观隐蔽、时好时坏、排查难度大,很多工程师反复更换元件仍无法解决,最终误判为 “板报废”。一、PCB 隐性故障核心成因…...
DragonBones与Godot集成:骨骼动画的可编程化实践
1. 为什么在Godot里用DragonBones不是“锦上添花”,而是“绕不开的刚需” 去年上线一个横版动作手游Demo时,美术团队交来一套20个角色、每个角色含8套动画(待机/跑动/跳跃/攻击/受击/死亡/闪避/必杀)的Spine资源。我兴冲冲导入God…...
随机森林算法在儿童出行方式预测中的实战应用与优化
1. 项目概述:用随机森林预测孩子怎么上学做城市交通规划或者做家长接送方案的时候,你肯定想过一个问题:孩子们到底是怎么上学的?是走路、骑车、坐公交还是家长开车送?这个问题看似简单,背后却牵扯到城市规划…...
OmenSuperHub:基于WMI BIOS控制的高性能笔记本硬件管理方案
OmenSuperHub:基于WMI BIOS控制的高性能笔记本硬件管理方案 【免费下载链接】OmenSuperHub Control Omen laptop performance, fan speeds, and keyboard lighting, and unlock power limits. 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub 在惠…...
InVideo插件深度解析:如何在Unreal Engine中实现高效视频流播放与录制
InVideo插件深度解析:如何在Unreal Engine中实现高效视频流播放与录制 【免费下载链接】InVideo 基于UE4实现的rtsp的视频播放插件 项目地址: https://gitcode.com/gh_mirrors/in/InVideo InVideo是一个基于Unreal Engine 5开发的RTSP视频播放插件࿰…...
别再只用鼠标了!用Leap Motion手势控制Unity游戏,保姆级配置避坑指南(2024版)
2024年Unity手势交互开发实战:Leap Motion从配置到游戏逻辑全解析在游戏开发领域,交互方式的创新往往能带来全新的体验。想象一下,玩家不再需要键盘鼠标,仅凭自然的手部动作就能操控游戏角色——这正是Leap Motion手势识别技术为U…...
从无线破解到PDF解密:盘点那些容易被忽略的‘非主流’密码审计场景与工具
密码安全审计的隐秘战场:从无线网络到加密文档的实战指南 当大多数人谈论密码安全时,脑海中浮现的往往是服务器登录、数据库访问这些企业级场景。然而在数字生活的每个角落,从家庭Wi-Fi到工作文档,密码保护的脆弱性同样可能成为安…...
国产麒麟系统上编译GDAL 3.2.1踩坑记:从PROJ6依赖缺失到Qt环境集成
麒麟系统GDAL 3.2.1编译实战:PROJ6依赖修复与Qt工程深度集成在国产操作系统生态中部署地理数据处理工具链,往往会遇到比常规Linux发行版更复杂的依赖问题。最近在麒麟系统上为北斗定位项目编译GDAL 3.2.1时,遭遇了经典的"PROJ 6 symbols…...
BetterNCM安装器终极指南:5分钟解锁网易云音乐无限潜能
BetterNCM安装器终极指南:5分钟解锁网易云音乐无限潜能 【免费下载链接】BetterNCM-Installer 一键安装 Better 系软件 项目地址: https://gitcode.com/gh_mirrors/be/BetterNCM-Installer 你是否觉得网易云音乐PC版功能有限,界面单调?…...
收藏干货|2026 版双非零基础入局大模型开发,RAG 与 Agent 就业上岸全攻略
日常总能收到不少初学伙伴的私信,大家普遍都有同一个疑惑:二本及普通院校学历,零基础入门 RAG、Agent 大模型应用开发,究竟能不能顺利入职?行业后续发展前景又如何? 本篇 2026 年全新内容,不空谈…...
