当前位置: 首页 > news >正文

【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++】特殊类设计类型转换

目录 &#x1f4a1;前言一&#xff0c;特殊类设计1. 请设计一个类&#xff0c;不能被拷贝2. 请设计一个类&#xff0c;只能在堆上创建对象3. 请设计一个类&#xff0c;只能在栈上创建对象4. 请设计一个类&#xff0c;不能被继承5. 请设计一个类&#xff0c;只能创建一个对象(单…...

为git 命令行 设置代理环境变量

http://t.csdnimg.cn/cAxkg 国内需要修改pinoko根目录下gitconfig文件&#xff0c;添加 [http]proxy http://127.0.0.1:1080 [https]proxy https://127.0.0.1:1080或者通过命令行配置&#xff1a; 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实现自动化工作流

前言 在这个快节奏的时代&#xff0c;我们每天都在与电脑打交道&#xff0c;重复着那些繁琐而单调的操作&#xff1b;你是否曾想过&#xff0c;能让电脑自己完成这些任务&#xff0c;而你则悠闲地喝着咖啡&#xff0c;享受着生活&#xff1f;今天&#xff0c;就让我们一起揭开一…...

大型语言模型微调 新进展-4篇 论文

1. Brevity is the soul of wit: Pruning long files for code generation 发布时间&#xff1a;2024-06-29链接&#xff1a;https://arxiv.org/abs/2407.00434机构&#xff1a;伦敦大学学院 (UCL) 本研究针对大型语言模型的代码生成任务中的数据清理问题进行了探索。研究发现…...

专业课140+杭电杭州电子科技大学843信号与系统考研经验电子信息与通信工程真题,大纲,参考书。

顺利上岸杭电&#xff0c;由于专业课考的不错140&#xff0c;群里不少同学希望分享一点经验&#xff0c;回头看看这一年考研复习&#xff0c;确实有得有失&#xff0c;总结一下自己的专业课复习经验&#xff0c;希望对大家有帮助&#xff0c;基础课考的没有专业好&#xff0c;而…...

php 中 (0 == ‘abc‘) 为真

https://andi.cn/page/621653.html...

MacOS Anaconda 安装教程及虚拟环境创建

一、下载 Anaconda 1、Anaconda 官网 2、清华大学开源软件镜像站 点 Date 按时间排序&#xff0c;根据自己 Mac 芯片类型下载对应最新版本的。 Intel 芯片的下载 x86_64 版本的Apple m1 芯片的下载 arm64 版本的 二、安装 Anaconda 将安装包下载到本地后&#xff0c;双击安…...

Mac快速配置ADB环境变量

ADB是进行 Androd 开发时很常用的调试工具&#xff0c;Android SDK 中就包含了该工具&#xff0c;所以如果安装了SDK那只需要在环境变量中配置 Android SDK 的路径即可&#xff0c;本文的环境配置也基于这种场景。 如果需要独立下载 ADB 工具&#xff0c;请参考下面网址&#x…...

Kylin的工作原理及使用分享

前言 在当今信息爆炸的时代&#xff0c;企业和研究机构每天都在生成和收集大量的数据。这些数据中蕴藏着巨大的商业价值和研究潜力&#xff0c;但要从中提取出有用的信息却并非易事。传统的数据处理和分析技术在面对如此庞大的数据量时&#xff0c;往往难以提供快速和有效的响…...

python 使用seleniumwire获取响应数据

seleniumwire 是一个在 Selenium WebDriver 基础上扩展的库&#xff0c;它允许你在使用 Selenium 进行网页自动化测试或爬虫时捕获和修改 HTTP 请求和响应。这对于需要分析网页数据或进行更复杂的网络交互的自动化任务特别有用。 以下是如何使用 seleniumwire 来获取响应数据的…...

用C语言实现双向链表

目录 一.双向链表的结构 二. 双向链表的实现 1. 在List.h中结构体的定义和各函数的声明 1.1 结构体&#xff08;节点&#xff09;的定义 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 配置&#xff1a;从零到精通 ESLint 是一个强大的代码检查工具&#xff0c;主要用于识别 JavaScript 和其他支持的语言中的常见编程错误&#xff0c;并强制执行一致的编码风格。自2013年6月由Nicholas C. Zakas创建以来&#xff0c;ESLint 已成为前端开发中不…...

BTC连续拉涨,击碎空头幻想

原创 | 刘教链 隔夜BTC继续拉涨&#xff0c;急破6万刀&#xff0c;“过了黄洋界&#xff0c;险处不须看”&#xff0c;一度逼近63k&#xff0c;目前暂于61-62k区间休整。从8月5日极限插针下探49k&#xff0c;仅仅3天多时间&#xff0c;就连续拉涨到了61k&#xff0c;总涨幅接近…...

【Spring】Sping笔记01

参考学习&#xff1a;b站浪飞yes ---------------------------------------------------- # 一、Spring 引入 **事务实现** java public class EmployeeServiceImpl implements IEmployeeService { public void save(Employee employee){ // 打开资源 /…...

Gridcontrol纵向/横向合并单元格

指定列值相同&#xff0c;纵向合并&#xff1a; this.gridView1.OptionsView.AllowCellMerge true;//启用合并列 // 启用指定合并列事件 this.gridView1.CellMerge new DevExpress.XtraGrid.Views.Grid.CellMergeEventHandler(gridView1_CellMerge);#region 合并指定的列 pri…...

从周杰伦的《青花瓷》三次更名看方文山的国学情怀与工匠精神

《青花瓷》三次更名&#xff0c;方文山的国学情怀与工匠精神 在华语乐坛上&#xff0c;周杰伦与方文山的合作堪称黄金组合&#xff0c;他们的作品不仅引领了流行音乐的潮流&#xff0c;更让传统文化焕发出新的生机。在这其中&#xff0c;《青花瓷》无疑是他们合作的经典之一&a…...

HATS:分层图注意力神经网络用于股票预测

HATS&#xff1a;分层图注意力神经网络用于股票预测 原创 QuantML QuantML 2024年08月09日 19:08 上海 Content 本文提出了一种名为HATS&#xff08;Hierarchical Graph Attention Network&#xff09;的分层图注意力网络&#xff0c;用于预测股市动向。HATS通过选择性地聚合…...

【日常记录-MySQL】MySQL设置root用户密码

Author&#xff1a;赵志乾 Date&#xff1a;2024-08-09 Declaration&#xff1a;All Right Reserved&#xff01;&#xff01;&#xff01; 1. 简介 MySQL8.0.30安装后启动&#xff0c;发现root用户尚未设置密码。以下是两种设置root用户密码的方式。 2. 示例 2.1 mysqladmin…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

Mac flutter环境搭建

一、下载flutter sdk 制作 Android 应用 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 1、查看mac电脑处理器选择sdk 2、解压 unzip ~/Downloads/flutter_macos_arm64_3.32.2-stable.zip \ -d ~/development/ 3、添加环境变量 命令行打开配置环境变量文件 ope…...

GraphRAG优化新思路-开源的ROGRAG框架

目前的如微软开源的GraphRAG的工作流程都较为复杂&#xff0c;难以孤立地评估各个组件的贡献&#xff0c;传统的检索方法在处理复杂推理任务时可能不够有效&#xff0c;特别是在需要理解实体间关系或多跳知识的情况下。先说结论&#xff0c;看完后感觉这个框架性能上不会比Grap…...