【智能指针二】智能指针互转
- 一、简述
- 二、static_pointer_cast:静态转换
- 三、dynamic_pointer_cast:动态转换
- 四、const_pointer_cast:
- 五、reinterpret_pointer_cast:
一、简述
智能指针的转换和普通指针的转换是一样的,只是用到的转换函数中间多了一个pointer,
- 比如普通指针用到的static_cast、dynamic_cast、const_cast和reinterpret_cast。
- 智能指针用到的与之对应的转换函数为:static_pointer_cast、dynamic_pointer_cast、const_pointer_cast和reinterpret_pointer_cast。
- 如果你看了智能指针的转换的实现方式,你会发现,他调用的函数也是普通指针的转换函数。
关键字 | 说明 |
---|---|
static_cast | 用于良性转换,一般不会导致意外发生,风险很低。 |
const_cast | 用于 const 与非 const、volatile 与非 volatile 之间的转换。 |
reinterpret_cast | 高度危险的转换,这种转换仅仅是对二进制位的重新解释,但是可以实现最灵活的 C++ 类型转换。 |
dynamic_cast | 用于类型安全的向下转型。或者向上转。 |
C++ static_cast、dynamic_cast、const_cast和reinterpret_cast
二、static_pointer_cast:静态转换
- 主要讲解下有继承关系的转换(基本类型的本文不涉及)
- 即可以向上转换(同隐式转换),也可以向下转换
#include <iostream>
#include <memory>
#include<string>
using namespace std;
class Parent;
class Child;
class Parent
{
public:
Parent() {} //暂时不明白为何子类需要需要父类的这个默认的构造函数,在此记录,后续研究
Parent(string name) {
m_name = name;
}
~Parent() {
cout << "~Parent()" << endl;
}
public:
virtual void func()
{
cout <<"m_name="<<m_name << ":i am a father." << endl<<endl;
}
public:
string m_name;;
};
class Child:public Parent
{
public:
Child(string name)
{
m_name = name;
}
~Child() {
cout << "~Child()" << endl;
}
public:
void func()
{
cout << "m_name=" << m_name << ":i am a son." << endl<<endl;
}
public:
string m_name;
};
int main()
{
shared_ptr<Parent> father(new Parent("father"));
shared_ptr<Child> son(new Child("son"));
// 隐式转换
shared_ptr<Parent> father1 = son;
cout << "爸爸1说" << endl;
father1->func();
// 向上转
shared_ptr<Parent> father2 = static_pointer_cast<Parent>(son);
cout << "爸爸2说" << endl;
father2->func();
// 向下转
shared_ptr<Child> son2 = static_pointer_cast<Child>(father);
cout << "儿子2说" << endl;
son2->func();
return 0;
}
输出
三、dynamic_pointer_cast:动态转换
- 主要讲解下有继承关系的转换(基本类型的本文不涉及)
- 即可以向上转换(同隐式转换),
- 也可以向下转换(可能成功也可能失败,同以下demo中的两个向下转换。和dynamic_cast一样。)如下,
- 1.把new出的子类指针赋值给父类指针,把此父类指针转换为子类指针,此情况转换正常
- 2.把new出的父类赋值给父类指针,把此父类指针转换为子类指针,此情况转换失败
- 避免运行时检查的开销。
#include <iostream>
#include <memory>
#include<string>
using namespace std;
class Parent;
class Child;
class Parent
{
public:
Parent() {} //暂时不明白为何子类需要需要父类的这个默认的构造函数,在此记录,后续研究
Parent(string name) {
m_name = name;
}
~Parent() {
cout << "~Parent()" << endl;
}
public:
virtual void func()
{
cout <<"m_name="<<m_name << ":i am a father." << endl<<endl;
}
public:
string m_name;;
};
class Child:public Parent
{
public:
Child() {}
Child(string name)
{
m_name = name;
}
~Child() {
cout << "~Child()" << endl;
}
public:
void func()
{
cout << "m_name=" << m_name << ":i am a son." << endl<<endl;
}
public:
string m_name;
};
int main()
{
shared_ptr<Parent> father(new Parent("father"));
shared_ptr<Child> son(new Child("son"));
// 隐式转换
shared_ptr<Parent> father1 = son;
cout << "爸爸1说" << endl;
father1->func();
// 向上转
shared_ptr<Parent> father2 = dynamic_pointer_cast<Parent>(son);
cout << "爸爸2说" << endl;
father2->func();
// 向下转
shared_ptr<Child> son2 = dynamic_pointer_cast<Child>(father);
cout << "儿子2说" << endl;
if (son2)
son2->func();
else
cout << "爸爸转儿子,son2 is null" << endl<<endl;
// 向下转
shared_ptr<Parent> father3(new Child("son"));
shared_ptr<Child> son3 = dynamic_pointer_cast<Child>(father3);
cout << "儿子3说" << endl;
if (son3)
son3->func();
else
cout << "爸爸转儿子,son3 is null" << endl << endl;
return 0;
}
输出
dynamic_pointer_cast 找不到官方的参考资料,但是可以可以从官方的dymanic_cast资料类推出以上转换规则。参考来自我的上一篇博客,以及cppreference.com/dynamic_cast
四、const_pointer_cast:
- 同const_cast作用一致,去掉const属性,变成可修改的。
- 如本文的demo,son的类型是const int类型的智能指针,原本是无法修改的,但是使用const_pointer_cast转换为int,就可以修改了。
- 网上很多关于const_pointer_cast的例子基本都是错误的,他们使用const_pointer_cast后,还修改原来的int指针,可以说是没有意义的,因为即使没有const_pointer_cast,原来的int指针也是可以修改的。比如https://cplusplus.com/reference/memory/const_pointer_cast/、https://learn.microsoft.com
#include <iostream>
#include <memory>
#include<string>
using namespace std;
int main()
{
shared_ptr<int> father(new int(10));
shared_ptr<const int> son(father);
// 此种情况,son是不可以直接改变值的,
cout << "儿子son的值" << endl;
cout << *son<<endl<<endl;
// 但是,const 的son,经过const_pointer_cast转换的son2就可以赋值了。
shared_ptr<int> son2 = const_pointer_cast<int>(son);
*son2 = 20;
cout << "儿子son2赋值后" << endl;
cout << *son2;
return 0;
}
输出
五、reinterpret_pointer_cast:
-
c++17和c++20新增的,目前找不到官方的demo,
-
具体同reinterpret_cast,区别在于此reinterpret_pointer_cast针对的是智能指针的转换。
-
reinterpret 是“重新解释”的意思,顾名思义,reinterpret_cast 这种转换仅仅是对二进制位的重新解释,不会借助已有的转换规则对数据进行调整,非常简单粗暴,所以风险很高。
-
reinterpret_cast 可以认为是 static_cast 的一种补充,一些 static_cast 不能完成的转换,就可以用 reinterpret_cast 来完成,例如两个具体类型指针之间的转换
-
简单来说,其他不敢转的,reinterpret_pointer_cast敢转,但是需要遵循场景要求,否则就会出现问题,具体场景参考reinterpret_cast的用法吧,因并reinterpret_pointer_cast没有找到官方的资料和用法。文章来源:https://uudwc.com/A/NZ6xk
#include <iostream>
#include <memory>
#include<string>
using namespace std;
class Parent
{
public:
Parent() {} //暂时不明白为何子类需要需要父类的这个默认的构造函数,在此记录,后续研究
Parent(string name) {
m_name = name;
}
~Parent() {
cout << "~Parent()" << endl;
}
public:
virtual void func()
{
cout << "m_name=" << m_name << ":i am a father." << endl << endl;
}
public:
string m_name;
int m_age = 30;
};
int main()
{
std::shared_ptr<std::int8_t[]> p(new std::int8_t[4]{ 1, 1, 1, 1 });
std::shared_ptr<std::int32_t[]> q = std::reinterpret_pointer_cast<std::int32_t[]>(p);
std::int32_t r = q[0];
cout << r<<endl;
shared_ptr<Parent> father(new Parent("father"));
// 将 shared_ptr<Parent> 转换为 shared_ptr<int>
shared_ptr<int> sq=reinterpret_pointer_cast<int>(father);
cout<<*sq<<endl;
shared_ptr<char> son(new char[]("father"));
// 将 shared_ptr<char> 转换为 shared_ptr<int>
shared_ptr<int> sq2 = reinterpret_pointer_cast<int>(son);
cout << *sq2<<endl;
return 0;
}
参考
C++ static_cast、dynamic_cast、const_cast和reinterpret_cast
【cmake实战十】c++从动态库(dll)导出类文章来源地址https://uudwc.com/A/NZ6xk