【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…...

高级Web安全技术(第二篇)
我们继续第二篇,继续深入了解web的安全 一、概述 在Web应用的开发与部署中,安全问题不仅是技术挑战,更是对系统整体架构的考验。本篇文章将继续深入探讨高级Web安全技术,重点关注API安全的最佳实践、OAuth的安全实施以及安全编码…...

前端实现文件下载常用几种方式
项目中前端下载一般分为两种情况: 后端直接提供一个文件地址,通过浏览器打开就可以下载。需要发送请求,后端返回二进制流数据,前端解析流数据,生成URL实现下载。 前端对应的实质是a标签和Blob文件下载,这…...

Isaac Lab 安装 (ubuntu22.04环境)
Windows下的安装见这篇博客: Isaac Lab 安装与初体验 (windows环境)-CSDN博客 ubuntu22.04下的安装与windows下十分类似,还是参考官方的,Installation using Isaac Sim Binaries Installation using Isaac Sim Bina…...

todoList清单(HTML+CSS+JavaScript)
🌏个人博客主页: 前言: 前段时间学习了JavaScript,然后写了一个todoList小项目,现在和大家分享一下我的清单以及如何实现的,希望对大家有所帮助 🔥🔥🔥文章专题ÿ…...

LVS集群实现四层负载均衡详解(以nat,dr模式为例)
目录 一、LVS集群的介绍 1、LVS 相关术语: 2、lvs四层负载均衡工作原理 3、相关名词概念 4、lvs集群的类型 二、lvs的nat模式 1、介绍: 2、数据逻辑: 3、nat实验部署 环境搭建: 1、lvs中要去打开内核路由功能,…...

七夕表白网页效果实现与解析
七夕是中国传统的情人节,是一个充满浪漫与爱的节日。在这个特别的日子里,用代码来表达心意也是一种独特且有趣的方式。本篇文章将带你一步步实现一个简单但充满心意的七夕表白网页。通过使用HTML、CSS和少量的JavaScript,我们将创建一个包含跳…...

人工智能算法工程师(高级)课程11-自然语言处理之NLP的语言模型-seq2seq模型,seq+注意力与代码详解
大家好,我是微学AI,今天给大家介绍一下人工智能算法工程师(高级)课程11-自然语言处理之NLP的语言模型-seq2seq模型,seq+注意力,word2vec与代码详解。本课程面向高级人工智能算法工程师,深入讲解自然语言处理(NLP)中的关键语言模型技术,包括seq2seq模型及其增强版加入注意力…...

从PyTorch官方的一篇教程说开去(6.2 - 张量 tensor 矩阵运算等)
您的进步和反馈是我写作最大的动力,小伙伴来个三连呗!共勉~ 话不多说,书接上文,需要温习的小伙伴请移步 - 从PyTorch官方的一篇教程说开去(6.1 - 张量 tensor 基本操作)-CSDN博客 借图镇楼 - 1 - 矩阵乘…...

【网络层】直连路由、静态路由、动态路由
文章目录 路由表直连路由直连路由 技术背景直连路由 实战训练 静态路由静态路由 技术背景静态路由 概述静态路由 配置命令静态路由 实战训练 动态路由动态路由 技术背景路由协议概述路由协议分类 路由表 路由表的形成,路由的来源: 路由来源备注直连路由…...

tkinter用法总结
Tkinter 是 Python 标准库中的一个模块,用于创建图形用户界面 (GUI)。它是 Python 中最常用的 GUI 库之一,因为它集成在 Python 的标准发行版中,无需额外安装即可使用。 一、基本用法 1. 简单示例 import tkinter as tk# 创建主窗口 root …...