一文讲全C++中类型转换操作符

2024-07-18 13:25:23 浏览数 (3)

类型转换是C 中一种非常常见的操作,为了保证类型转换的安全性和有效性,C 提出了四种类型转换操作符,通常称之为常规转换操作符。在共享指针出来后,为实现共享指针的转换,提出共享指针支持的四种转换操作符。

常规类型转换操作符

忏悔转换操作符由如下四种:static_cast、dynamic_cast、const_cast和reinterpret_cast。每种转换操作符尤其特定的适用场景。

static_cast

static_cast是一种编译期转换,在编译时进行类型检查并执行类型转换。它主要用于以下几种情况:

  • 用于较明显的类型转换,例如基本数据类型之间的转换。
  • 用于向上转型(Upcasting)和向下转型(Downcasting)之间的转换,但不进行运行时类型检查。
  • 用于将指针或引用从派生类转换为基类。

示例代码:

代码语言:javascript复制
int num = 10;
double convertedNum = static_cast<double>(num);

Base* basePtr = newDerived();
Derived* derivedPtr = static_cast<Derived*>(basePtr);

dynamic_cast

dynamic_cast是一种运行时转换,在运行时进行类型检查并执行类型转换。它主要用于以下几种情况:

  • 用于多态类型之间的向上转型和向下转型,并进行安全的运行时类型检查。
  • 当转换的目标类型为指针时,如果转换失败,dynamic_cast会返回空指针;当转换的目标类型为引用时,如果转换失败,dynamic_cast会抛出异常。

示例代码:

代码语言:javascript复制
Base* basePtr = newDerived();
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);

if (derivedPtr) {
    // 转换成功
} else {
    // 转换失败
}

const_cast

const_cast用于添加或移除指针或引用的const或volatile修饰符。它主要用于以下几种情况:

  • 用于将const或volatile指针或引用转换为非const或非volatile。
  • 用于解除对象的const限制,以便在其上进行修改操作。

示例代码:

代码语言:javascript复制
constint num = 10;
int& ref = const_cast<int&>(num);
ref = 20; // 合法,虽然num为const,但通过const_cast修改了引用

int a =10;
volatileint* p = &a;
auto  b = const_cast<int*>(p);

reinterpret_cast

reinterpret_cast是一种比较底层的转换,主要用于不同类型之间的强制转换,不进行类型检查,可能会导致未定义的行为。它主要用于以下几种情况:

  • 用于将一个指针类型转换为另一种不兼容的指针类型。
  • 用于将指针类型转换为整数类型或整数类型转换为指针类型,但需要注意平台相关性和安全性。

示例代码:

代码语言:javascript复制
int num = 10;
double* ptr = reinterpret_cast<double*>(&num);

共享指针转换操作符

共享指针std::shared_ptr支持的类型转换操作符:std::static_pointer_cast、std::dynamic_pointer_cast、std::const_pointer_cast、std::reinterpret_pointer_cast,这四种共享指针的类型转换操作符和常规类型转换操作符一一对应,难道他们之间有什么关联吗,show me the code

代码语言:javascript复制
//msvc源码,有删减
_EXPORT_STD template <class _Ty1, class _Ty2>
_NODISCARD shared_ptr<_Ty1> static_pointer_cast(const shared_ptr<_Ty2>& _Other) noexcept {
    // static_cast for shared_ptr that properly respects the reference count control block
    const auto _Ptr = static_cast<typename shared_ptr<_Ty1>::element_type*>(_Other.get());
    return shared_ptr<_Ty1>(_Other, _Ptr);
}

_EXPORT_STD template <class _Ty1, class _Ty2>
_NODISCARD shared_ptr<_Ty1> const_pointer_cast(const shared_ptr<_Ty2>& _Other) noexcept {
    // const_cast for shared_ptr that properly respects the reference count control block
    const auto _Ptr = const_cast<typename shared_ptr<_Ty1>::element_type*>(_Other.get());
    return shared_ptr<_Ty1>(_Other, _Ptr);
}

_EXPORT_STD template <class _Ty1, class _Ty2>
_NODISCARD shared_ptr<_Ty1> reinterpret_pointer_cast(const shared_ptr<_Ty2>& _Other) noexcept {
    // reinterpret_cast for shared_ptr that properly respects the reference count control block
    const auto _Ptr = reinterpret_cast<typename shared_ptr<_Ty1>::element_type*>(_Other.get());
    return shared_ptr<_Ty1>(_Other, _Ptr);
}

_EXPORT_STD template <class _Ty1, class _Ty2>
_NODISCARD shared_ptr<_Ty1> dynamic_pointer_cast(const shared_ptr<_Ty2>& _Other) noexcept {
    // dynamic_cast for shared_ptr that properly respects the reference count control block
    const auto _Ptr = dynamic_cast<typename shared_ptr<_Ty1>::element_type*>(_Other.get());

    if (_Ptr) {
        return shared_ptr<_Ty1>(_Other, _Ptr);
    }

    return {};
}

由以上代码可知,共享指针支持的类型转换实则是一层封装,当且仅当裸指针支持对应的类型转换时,方可实现共享指针的类型转换。

基于此,共享指针的类型转换操作符与规指针类型转换操作的符的适用场景、注意事项相同,

总结

在C 中,类型转换操作符各具特点且各自有自己的适用场景,应根据实际情况选择合适的转换方式。为确保代码的正确性和安全性应合理使用这些转换操作符,应注意类型的兼容性和转换的安全性,避免导致未定义的行为和潜在的错误。

0 人点赞