当前位置:首页 > 科技  > 软件

C++ 20类型转换指南:使用场景与优秀实践

来源: 责编: 时间:2023-11-20 08:58:11 381观看
导读类型转换 (Casts)C++ 提供了五种特定的类型转换:const_cast<>()、static_cast<>()、reinterpret_cast<>()、dynamic_cast<>() 和 C++20 引入的 std::bit_cast<>()。请注意,旧的 C 风格类型转换(如 (int)myFloat)在 C++ 中

类型转换 (Casts)

C++ 提供了五种特定的类型转换:const_cast<>()、static_cast<>()、reinterpret_cast<>()、dynamic_cast<>() 和 C++20 引入的 std::bit_cast<>()。qlG28资讯网——每日最新资讯28at.com

请注意,旧的 C 风格类型转换(如 (int)myFloat)在 C++ 中仍然有效,并在现有代码库中广泛使用。C 风格的类型转换涵盖了所有四种 C++ 类型转换,因此它们更容易出错,因为您试图实现的目的并不总是显而易见的,可能会得到意外的结果。我强烈建议您在新代码中只使用 C++ 风格的类型转换,因为它们更安全,且在代码中更加突出。qlG28资讯网——每日最新资讯28at.com

qlG28资讯网——每日最新资讯28at.com

虚拟基类

模糊基类出现在多个父类共有一个共同的父类时。推荐的解决方案是确保共享的父类自身不具有任何功能。这样,其方法永远不会被调用,从而避免了歧义问题。C++ 还有另一种机制,称为虚拟基类,用于解决您希望共享的父类具有自己功能的情况。qlG28资讯网——每日最新资讯28at.com

如果共享的父类是一个虚拟基类,则不会有任何歧义。以下代码在 Animal 基类中添加了一个 sleep() 方法,并修改了 Dog 和 Bird 类,使它们作为虚拟基类从 Animal 继承。如果不使用虚拟基类,对 DogBird 对象的 sleep() 调用将是模糊的,并会生成编译器错误,因为 DogBird 将具有两个 Animal 子对象,一个来自 Dog,一个来自 Bird。然而,当 Animal 被虚拟继承时,DogBird 只有一个 Animal 类的子对象,因此调用 sleep() 不会有歧义。qlG28资讯网——每日最新资讯28at.com

class Animal {public:    virtual void eat() = 0;    virtual void sleep() { cout << "zzzzz...." << endl; }};class Dog : public virtual Animal {public:    virtual void bark() { cout << "Woof!" << endl; }    void eat() override { cout << "The dog ate." << endl; }};class Bird : public virtual Animal {public:    virtual void chirp() { cout << "Chirp!" << endl; }    void eat() override { cout << "The bird ate." << endl; }};class DogBird : public Dog, public Bird {public:    void eat() override { Dog::eat(); }};int main() {    DogBird myConfusedAnimal;    myConfusedAnimal.sleep(); // 因为虚拟基类而不模糊}

注意:虚拟基类是避免类层次结构中歧义的好方法。qlG28资讯网——每日最新资讯28at.com

qlG28资讯网——每日最新资讯28at.com

类型转换 (Casts)

C++ 提供了五种特定的类型转换:const_cast<>()、static_cast<>()、reinterpret_cast<>()、dynamic_cast<>() 和 C++20 引入的 std::bit_cast<>()。第一种在第 1 章中讨论过。第 1 章还介绍了用于某些基本类型之间转换的 static_cast<>(),但在继承的上下文中还有更多内容。现在您已经熟悉编写自己的类并理解类继承,是时候更仔细地看看这些类型转换了。qlG28资讯网——每日最新资讯28at.com

请注意,旧的 C 风格类型转换(如 (int)myFloat)在 C++ 中仍然有效,并在现有代码库中广泛使用。C 风格的类型转换涵盖了所有四种 C++ 类型转换,因此它们更容易出错,因为您试图实现的目的并不总是显而易见的,可能会得到意外的结果。我强烈建议您在新代码中只使用 C++ 风格的类型转换,因为它们更安全,且在代码中更加突出。qlG28资讯网——每日最新资讯28at.com

static_cast()

(1) 使用场景qlG28资讯网——每日最新资讯28at.com

static_cast()用于执行语言直接支持的显式转换。例如,将int转换为double以避免整数除法:qlG28资讯网——每日最新资讯28at.com

int i { 3 };int j { 4 };double result { static_cast<double>(i) / j };

static_cast() 也可用于执行因用户定义的构造函数或转换例程而允许的显式转换。例如,如果类 A 有一个接受 B 对象的构造函数,则可以使用 static_cast() 将 B 对象转换为 A 对象。qlG28资讯网——每日最新资讯28at.com

(2) 在继承中的应用qlG28资讯网——每日最新资讯28at.com

static_cast()可用于继承层次结构中的向下转型:qlG28资讯网——每日最新资讯28at.com

class Base { /* ... */ };class Derived : public Base { /* ... */ };Base* b { nullptr };Derived* d { new Derived{} };b = d; // 向上转型,不需要转换。d = static_cast<Derived*>(b); // 向下转型,需要转换。

(3) 注意事项qlG28资讯网——每日最新资讯28at.com

  • static_cast() 不执行运行时类型检查。可以将任何 Base 指针转换为 Derived 指针,即使 Base 实际上不是 Derived。
  • static_cast() 不是万能的,它不能将一种类型的指针转换为另一种完全无关的类型的指针,也不能在没有转换构造函数的情况下直接将一种类型的对象转换为另一种类型的对象。

reinterpret_cast()

(1) 使用场景qlG28资讯网——每日最新资讯28at.com

  • reinterpret_cast() 比 static_cast() 更强大但同时也更不安全。它用于执行 C++ 类型规则技术上不允许的某些转换。
  • 可以用来将一种类型的引用转换为另一种类型的引用,即使类型之间完全无关。
  • 常用于将指针类型转换为任何其他指针类型,包括将任何类型的指针转换为 void*。

(2) 注意事项qlG28资讯网——每日最新资讯28at.com

  • 使用 reinterpret_cast() 要格外小心,因为它允许你在不执行任何类型检查的情况下进行转换。
  • 可以用 reinterpret_cast() 将指针转换为足够大以容纳它的整型类型,反之亦然。但是,尝试将 64 位指针转换为 32 位整数会导致编译错误。

std::bit_cast()

(1) 特点qlG28资讯网——每日最新资讯28at.com

  • std::bit_cast() 是 C++20 中引入的,定义在 <bit> 头文件中。
  • 它是标准库中唯一的类型转换,其他类型转换是 C++ 语言本身的一部分。
  • bit_cast() 类似于 reinterpret_cast(),但它创建一个给定目标类型的新对象,并将源对象的位复制到这个新对象中。它有效地将源对象的位解释为目标对象的位。
  • bit_cast() 要求源对象和目标对象的大小相同且都是平凡可复制的。

(2) 示例qlG28资讯网——每日最新资讯28at.com

float asFloat { 1.23f };auto asUint { bit_cast<unsigned int>(asFloat) };if (bit_cast<float>(asUint) == asFloat) {    cout << "Roundtrip success." << endl;}

(3) 应用场景qlG28资讯网——每日最新资讯28at.com

bit_cast() 的一个用例是用于平凡可复制类型的二进制 I/O。例如,可以将这些类型的单个字节写入文件,读取文件时,可以使用 bit_cast() 正确解释从文件读取的字节。qlG28资讯网——每日最新资讯28at.com

平凡可复制类型通常具有以下特征:qlG28资讯网——每日最新资讯28at.com

qlG28资讯网——每日最新资讯28at.com

qlG28资讯网——每日最新资讯28at.com

  • 无自定义析构函数:类型没有自定义的析构函数。
  • 无自定义或虚拟构造函数:类型没有自定义的构造函数,也没有虚拟构造函数。
  • 无虚函数和虚基类:类型不包含虚函数,并且不从虚基类继承。
  • 可简单拷贝其状态:类型的所有成员可以通过简单的内存拷贝来复制,没有需要特殊处理的成员(如指针或动态分配的资源)。

dynamic_cast()

(1) 特点qlG28资讯网——每日最新资讯28at.com

  • dynamic_cast() 在继承层次结构中提供了运行时类型检查。
  • 它可以用于转换指针或引用。
  • 如果转换没有意义,dynamic_cast() 将返回空指针(对于指针版本)或抛出 std::bad_cast 异常(对于引用版本)。

(2) 示例qlG28资讯网——每日最新资讯28at.com

Base* b;Derived* d { new Derived{} };b = d;d = dynamic_cast<Derived*>(b);Base base;Derived derived;Base& br { base };try {    Derived& dr { dynamic_cast<Derived&>(br) };} catch (const bad_cast&) {    cout << "Bad cast!" << endl;}

(3) 与其他类型转换的区别qlG28资讯网——每日最新资讯28at.com

  • 与 static_cast() 或 reinterpret_cast() 不同,dynamic_cast() 执行运行时(动态)类型检查,而后者即使转换错误也会执行转换。
  • 为了使用 dynamic_cast(),你的类必须至少有一个虚拟方法。如果类没有虚拟表(vtable),尝试使用 dynamic_cast() 将导致编译错误。

C++ 类型转换总结

情境
qlG28资讯网——每日最新资讯28at.com

推荐的转换方法
qlG28资讯网——每日最新资讯28at.com

说明
qlG28资讯网——每日最新资讯28at.com

移除 const 属性qlG28资讯网——每日最新资讯28at.com

const_cast()qlG28资讯网——每日最新资讯28at.com

用于移除对象的 const 属性qlG28资讯网——每日最新资讯28at.com

语言直接支持的显式转换
qlG28资讯网——每日最新资讯28at.com

static_cast()qlG28资讯网——每日最新资讯28at.com

例如,从 int 转换到 double 或 boolqlG28资讯网——每日最新资讯28at.com

用户定义的构造函数或转换支持的显式转换
qlG28资讯网——每日最新资讯28at.com

static_cast()qlG28资讯网——每日最新资讯28at.com

用于用户定义的转换
qlG28资讯网——每日最新资讯28at.com

一个类的对象转换为另一个(无关)类的对象
qlG28资讯网——每日最新资讯28at.com

bit_cast()qlG28资讯网——每日最新资讯28at.com

用于无关类之间的对象转换
qlG28资讯网——每日最新资讯28at.com

同一继承层次中的类的指针对象转换
qlG28资讯网——每日最新资讯28at.com

dynamic_cast() (推荐) 或 static_cast()qlG28资讯网——每日最新资讯28at.com

用于继承层次中的指针对象转换
qlG28资讯网——每日最新资讯28at.com

同一继承层次中的类的引用对象转换
qlG28资讯网——每日最新资讯28at.com

dynamic_cast() (推荐) 或 static_cast()qlG28资讯网——每日最新资讯28at.com

用于继承层次中的引用对象转换
qlG28资讯网——每日最新资讯28at.com

不相关类型的指针转换
qlG28资讯网——每日最新资讯28at.com

reinterpret_cast()qlG28资讯网——每日最新资讯28at.com

用于完全不相关的指针类型之间的转换
qlG28资讯网——每日最新资讯28at.com

不相关类型的引用转换
qlG28资讯网——每日最新资讯28at.com

reinterpret_cast()qlG28资讯网——每日最新资讯28at.com

用于完全不相关的引用类型之间的转换
qlG28资讯网——每日最新资讯28at.com

函数指针之间的转换
qlG28资讯网——每日最新资讯28at.com

reinterpret_cast()qlG28资讯网——每日最新资讯28at.com

用于函数指针之间的转换
qlG28资讯网——每日最新资讯28at.com

注意事项

  • 使用 const_cast() 应谨慎,因为它改变了对象的 const 性质。
  • static_cast() 是最常用的转换类型,适用于许多标准和用户定义的转换。
  • bit_cast() 用于位级别的类型转换,要求源和目标类型大小相同且都是平凡可复制的。
  • dynamic_cast() 在继承层次中提供运行时类型检查,但要求类至少有一个虚拟方法。
  • reinterpret_cast() 提供更广泛的转换能力,但也带来更高的风险,因为它不执行类型检查。

qlG28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-31013-0.htmlC++ 20类型转换指南:使用场景与优秀实践

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Go vs Rust:文件上传性能比较

下一篇: C++14中的成员初始值设定项与聚合功能详解

标签:
  • 热门焦点
  • MIX Fold3包装盒泄露 新机本月登场

    小米的全新折叠屏旗舰MIX Fold3将于本月发布,近日该机的真机包装盒在网上泄露。从图上来看,新的MIX Fold3包装盒在外观设计方面延续了之前的方案,变化不大,这也是目前小米旗舰
  • 7月安卓手机性能榜:红魔8S Pro再夺榜首

    7月份的手机市场风平浪静,除了红魔和努比亚带来了两款搭载骁龙8Gen2领先版处理器的新机之外,别的也想不到有什么新品了,这也正常,通常6月7月都是手机厂商修整的时间,进入8月份之
  • CSS单标签实现转转logo

    转转品牌升级后更新了全新的Logo,今天我们用纯CSS来实现转转的新Logo,为了有一定的挑战性,这里我们只使用一个标签实现,将最大化的使用CSS能力完成Logo的绘制与动画效果。新logo
  • 一年经验在二线城市面试后端的经验分享

    忠告这篇文章只适合2年内工作经验、甚至没有工作经验的朋友阅读。如果你是2年以上工作经验,请果断划走,对你没啥帮助~主人公这篇文章内容来自 「升职加薪」星球星友 的投稿,坐
  • 阿里瓴羊One推出背后,零售企业迎数字化新解

    作者:刘旷近年来随着数字经济的高速发展,各式各样的SaaS应用服务更是层出不穷,但本质上SaaS大多局限于单一业务流层面,对用户核心关切的增长问题等则没有提供更好的解法。在Saa
  • 造车两年股价跌六成,小米的估值逻辑变了吗?

    如果从小米官宣造车后的首个交易日起持有小米集团的股票,那么截至2023年上半年最后一个交易日,投资者将浮亏59.16%,同区间的恒生科技指数跌幅为52.78%
  • 信通院:小米、华为等11家应用商店基本完成APP签名及验签工作

    中国信通院表示,目前,小米、华为、OPPO、vivo、360手机助手、百度手机助手、应用宝、豌豆荚和努比亚等9家应用商店,以及抖音和快手2家新型应用分发平
  • 三星电子Q2营收60万亿韩元 存储业务营收同比仍下滑超过50%

    7月27日消息,据外媒报道,从三星电子所发布的财报来看,他们主要利润来源的存储芯片业务在今年二季度仍不乐观,营收同比仍在大幅下滑,所在的设备解决方案
  • Android 14发布:首批适配机型公布

    5月11日消息,谷歌在今天凌晨举行了I/O大会,本次发布会谷歌带来了自家的AI语言模型PaLM 2、谷歌Pixel Fold折叠屏、谷歌Pixel 7a手机,同时发布了Androi
Top