特殊类的设计、C++四种类型转换

news/2024/9/23 20:10:44/

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

特殊类的设计

设计一个类,不能被拷贝

设计一个类,只能在堆上创建对象

设计一个类,只能在栈上创建对象

类型转换

 为什么C++需要四种类型转换

static_cast

reinterpret_cast

const_cast

dynamic_cast


特殊类的设计

设计一个类,不能被拷贝

拷贝只会发生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上

=delete,表示让编译器删除掉该默认成员函数

class CopyBan
{
// ...
CopyBan(const CopyBan&)=delete;
CopyBan& operator=(const CopyBan&)=delete;
//...
};
设计一个类,只能在堆上创建对象

要设计一个类,只能在堆上创建对象,你可以通过私有化构造函数和析构函数,并提供一个静态公有的静态成员函数来实现。这个静态成员函数负责在堆上分配对象,并返回指向该对象的指针。然后,你可以使用 delete 关键字来释放对象。

#include <iostream>
class HeapOnly {
private:// 私有化构造函数和析构函数HeapOnly() {}~HeapOnly() {}
public:// 静态成员函数,用于在堆上创建对象static HeapOnly* createObject() {return new HeapOnly();}// 静态成员函数,用于在堆上创建对象static void destroyObject(HeapOnly* obj) {delete obj;}// 其他公有成员函数void showMessage() {std::cout << "HeapOnly object created on heap!" << std::endl;}
};int main() {// 在堆上创建对象HeapOnly* obj = HeapOnly::createObject();// 使用对象obj->showMessage();// 释放对象HeapOnly::destroyObject(obj);return 0;
}

在这个示例中,HeapOnly 类的构造函数和析构函数被私有化,防止在栈上或全局上创建对象。而 createObject 静态成员函数允许在堆上创建对象,并返回指向该对象的指针。在 main 函数中,我们通过调用 createObject 函数在堆上创建了对象,然后使用对象的成员函数,并最后使用 delete 关键字释放了对象。

设计一个类,只能在栈上创建对象

如果一个类重载了new,那么用new创建类对象,就会调用这个重载new

class StackOnly
{
public:
static StackOnly CreateObj()
{
return StackOnly();
}
// 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉
// StackOnly obj = StackOnly::CreateObj();
// StackOnly* ptr3 = new StackOnly(obj);
void* operator new(size_t size) = delete;
void operator delete(void* p) = delete;
private:
StackOnly()
:_a(0)
{}
private:
int _a;
};

类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。
1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
2. 显式类型转化:需要用户自己处理

void Test ()
{
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);
} 

缺点:转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换

 为什么C++需要四种类型转换

C风格的转换格式很简单,但是有不少缺点的:
1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
2. 显式类型转换将所有情况混合在一起,代码不够清晰
因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格

标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:
static_cast、reinterpret_cast、const_cast、dynamic_cast

static_cast

static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用

注意:static_cast,但它不能用于两个不相关的类型进行转换

static_cast 主要用于以下几种情况:

1. 类型转换:将一个类型转换为另一个相关的类型。

2. 修正符号:将无符号类型转换为有符号类型,或者将有符号类型转换为无符号类型。

3. 避免隐式类型转换:在一些情况下,C++会执行隐式的类型转换,而 static_cast 可以明确地指定类型转换的行为,提高代码的可读性和可维护性。

以下是 static_cast 的基本语法:

result = static_cast<new_type>(expression);
result 是转换后的结果
new_type 是要转换成的新类型
expression 是要转换的表达式。

例如,将一个 int 类型转换为 double 类型:

int x = 10;
double y = static_cast<double>(x);
reinterpret_cast

使用 reinterpret_cast 进行类型转换时,编译器会强制执行转换,而不进行任何类型检查。这使得 reinterpret_cast 是最不安全的类型转换之一,因为它允许将任何指针类型转换为任何其他指针类型,即使它们在语义上没有关联。

reinterpret_cast 主要用于以下情况:

1. 将一个指针转换为另一个不同类型的指针,通常用于在底层进行类型转换,例如将 void* 指针转换为其他类型的指针。

2. 将一个指针转换为一个整数类型,或将一个整数类型转换为一个指针。这种转换通常用于处理指针地址的表示或存储。

以下是 reinterpret_cast 的基本语法:

result = reinterpret_cast<new_type>(expression);result 是转换后的结果
new_type 是要转换成的新类型
expression 是要转换的表达式

事例

double d = 12.34;
int a = static_cast<int>(d);
cout << a << endl;// 这里使用static_cast会报错,应该使用reinterpret_cast
//int *p = static_cast<int*>(a);
int *p = reinterpret_cast<int*>(a);
const_cast

使用 const_cast 进行类型转换时,编译器会修改表达式的常量性,但不会修改其值。这意味着通过 const_cast 转换后的指针或引用可以修改对象的值,即使原始对象被声明为常量也是如此。

const_cast 主要用于以下情况:

1. 去除指向常量对象的指针或引用的常量性,以便修改对象的值。

2. 添加指向非常量对象的指针或引用的常量性,以防止修改对象的值。

以下是 const_cast 的基本语法:

result = const_cast<new_type>(expression);result 是转换后的结果
new_type 是要转换成的新类型
expression 是要转换的表达式

事例

const int a=2;
int* p=const_cast<int*>(&a);(*p)++;//a++;//这里的a仍然不能修改,const int类型cout<<a<<endl;
cout<<*p<<endl;cout<<&a<<endl;
cout<<p<<endl;结果:
2
3
0x7ffeefbff3f8
0x7ffeefbff3f8为什么*p和a的值不一样呢?这是编译器做的优化
如果将a定义为volatile const int a=2;结果:
3
3
0x7ffeefbff3f8//&a的值这里大家和我的可能不一样,我在输出a的地址时,加了强制转换cout<<(int*)&a<<endl,我之所以强制转换,因为cout的匹配出了问题
0x7ffeefbff3f8
dynamic_cast

dynamic_cast 只能用于具有虚函数的类(即多态类),并且在运行时进行类型检查。它会检查所请求的类型是否与对象的实际类型兼容,如果兼容,则执行转换,否则返回空指针(对指针进行转换时)或抛出 std::bad_cast 异常(对引用进行转换时)。

dynamic_cast 主要用于以下情况:

1. 将指向基类的指针或引用转换为指向派生类的指针或引用。

2. 在运行时进行类型安全的向下转换,并且需要检查转换是否有效。

以下是 dynamic_cast 的基本语法:

result = dynamic_cast<new_type>(expression);result 是转换后的结果
new_type 是要转换成的新类型
expression 是要转换的表达式

事例

class A
{
public :
virtual void f(){}
};
class B : public A
{};
void fun (A* pa)
{
// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
B* pb1 = static_cast<B*>(pa);
B* pb2 = dynamic_cast<B*>(pa);
cout<<"pb1:" <<pb1<< endl;
cout<<"pb2:" <<pb2<< endl;
}
int main ()
{
A a;
B b;
fun(&a);
fun(&b);
return 0;
}

 🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸 


http://www.ppmy.cn/news/1430734.html

相关文章

双线性插值计算手动实现以及原理

双线性插值计算手动实现以及原理 代码原理 代码 先贴代码吧&#xff0c;原理其实也比较简单&#xff0c;看代码基本也就理解了&#xff0c;时间太晚了&#xff0c;原理后续再补吧。 import torch from torch.nn import functional as F import numpy as np from itertools im…

Rust 模式匹配中的 和 ref

一、Rust & 和 ref 1.Rust的ref有什么用 根据Rust官方文档https://doc.rust-lang.org/std/keyword.ref.html Rust ref 主要用在模式匹配match的所有权问题中。 ref在 Rust中&#xff0c;也是声明一个指针类型变量&#xff0c;进一步说明ref和&在其它方面区别&#xf…

AI重建粒子轨迹,发现新物理学

目录 二Sora冲击还没来&#xff0c;但智能家居人已经开始焦虑了&#xff01; 一、智能家居新革命&#xff1a;AIoH 二、AI技术接入智能家居&#xff0c;未来价值几何&#xff1f; 三、AI 智能家居&#xff0c;不是纸上谈兵 四、结语 电子学在核物理领域从来都不是一帆风顺…

【Linux】权限(shell运行原理、概念,Linux权限)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/qinjh_/category_12625432.html 目录 shell命令以及运行原理 创建和删除用户 创建新普通用户 删除用户 Linux权…

知道做到 一篇总结学习方法的笔记

元数据 [!abstract] 知道做到&#xff1a;跃迁式学习 书名&#xff1a; 知道做到&#xff1a;跃迁式学习作者&#xff1a; 彼得•霍林斯简介&#xff1a; 学习是改善你的生活环境、成为你想成为的人的关键。科学的方法能加速学习进程&#xff0c;让你事半功倍。技能、信息和能力…

Docker搭建NetbootXYZ

NetbootXYZ Docker 镜像功能介绍 NetbootXYZ 是一个开源的 PXE 引导服务器&#xff0c;用于网络引导操作系统安装。它支持多种操作系统的网络安装&#xff0c;如 Ubuntu、Debian、Windows 等。NetbootXYZ 提供了一个 Web 界面来管理网络引导过程&#xff0c;包括设置网络启动选…

[大模型]Qwen-7B-Chat WebDemo

Qwen-7B-Chat WebDemo 环境准备 在autodl平台中租一个3090等24G显存的显卡机器&#xff0c;如下图所示镜像选择PyTorch–>2.0.0–>3.8(ubuntu20.04)–>11.8 接下来打开刚刚租用服务器的JupyterLab&#xff0c;并且打开其中的终端开始环境配置、模型下载和运行demo…

类似nohup在windows通过cmd后台运行进程方法

Linux后台运行进程时&#xff0c;通常使用如下方法&#xff1a; nohup "运行的内容" &windows相应功能的命令行如下(此方法进程有页面&#xff0c;可能会在桌面展示&#xff0c;关闭窗口后进程消失。 call start /min "n" "运行的内容"cmd…