iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++基础入门篇之强制转换讲解
  • 802
分享到

C++基础入门篇之强制转换讲解

2023-06-07 13:06:06 802人浏览 薄情痞子
摘要

本篇内容主要讲解“c++基础入门篇之强制转换讲解”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++基础入门篇之强制转换讲解”吧!引言假设有基类 A,包含了虚函数 func1,以及有派生类 B,

本篇内容主要讲解“c++基础入门篇之强制转换讲解”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++基础入门篇之强制转换讲解”吧!

引言

假设有基类 A,包含了虚函数 func1,以及有派生类 B,继承于类 A,派生类 B 中实现了函数 func1。此时可以用 A 类型的指针指向 B 类型的对象,并用 A 类型的指针调用 B 类型对象中的函数 func1。这时,就形成了多态。包含虚函数的类 A,我们也称为多态类。

由于派生类 B 完整包含了 基类 A 的所有定义,将 B 类型的指针转换为 A 类型的指针总是安全的。

而将 A 类型的指针强制转换为 B 类型的指针时,如果 A 类型指针指向的对象确实为 B 类型的对象,那么转换也是安全的。此时,该 B 类型对象被称为完整对象(complete object)。

强制转换有哪些类型?

C++ 包含了以下几种强制转换运算符,这些运算符用于消除老式 C 语言转换中的存在的歧义和隐患:

  • dynamic_cast

  • static_cast

  • const_cast

  • reinterpret_cast

  • safe_cast

本文会着重介绍如何使用 dynamic_cast 和 static_cast。

提醒:

除非必须,不要使用 const_cast 和 reinterpret_cast,因为它们存在一些老式 C 语言转换中的隐患。

dynamic_cast 运算符

语法:

 dynamic_cast <type-id> (expression)

type-id 必须是一个指针或者引用,指向/引用已定义的类类型或者 void。如果type-id 是指针,则 expression 必须也为指针类型,如果 type-id 是引用,expression 必须为左值类型。

如果 type-id 是 void*,那么在运行时将检测 expression 的实际类型。其结果返回 expression 指向的完整对象。

如非需要,现代 C++ 中应该避免使用 void 指针,因为容易出错。

下面看些示例,了解 dynamic_cast 的使用方式。

示例1:

class Root { };class Base : public Root { };class Derived : public Base { };void f(Derived* pd) { Base* pb = dynamic_cast<Base*>(pd); // ok: Base is a direct base class         // pb points to Base subobject of pd Root* pr = dynamic_cast<Root*>(pd); // ok: Root is an indirect base class         // pr points to Root subobject of pd}

示例1 中提到了子对象(subobject)的概念,注意与子类型进行区分:

  • Root 类型包含子类型 Base,Base 类型包含子类型 Derived。

  • Derived 对象包含了 Base 类型的子对象,Base 类型的子对象又包含了 Root 类型的子对象。

再联系下前面说的:派生类完整包含了基类的所有定义。

示例2:

class B {virtual void f();};class D : public B {virtual void f();};void f() { B* pb = new D; // unclear but ok B* pb2 = new B; D* pd = dynamic_cast<D*>(pb); // ok: pb actually points to a D D* pd2 = dynamic_cast<D*>(pb2); // pb2 was nullptr.}

示例2 中 通过 dynamic_cast 转换为 pd2 时,不会报错,返回 nullptr。但如果同样地情况转换的对象是引用类型,那么运行时会抛出 std::bad_cast 异常。如果 pb2 指向/引用的对象无效,同样也会抛出异常。

示例3:

#include <stdio.h>#include <iOStream>struct A { virtual void test() {  printf_s("in A\n"); }};struct B : A { virtual void test() {  printf_s("in B\n"); } void test2() {  printf_s("test2 in B\n"); }};struct C : B { virtual void test() {  printf_s("in C\n"); } void test2() {  printf_s("test2 in C\n"); }};void Globaltest(A& a) { try {  C &c = dynamic_cast<C&>(a);  printf_s("in GlobalTest\n"); } catch(std::bad_cast) {  printf_s("Can't cast to C\n"); }}int main() { A *pa = new C; A *pa2 = new B; pa->test(); B * pb = dynamic_cast<B *>(pa); if (pb)  pb->test2(); C * pc = dynamic_cast<C *>(pa2); if (pc)  pc->test2(); C ConStack; Globaltest(ConStack); // will fail because B knows nothing about C B BonStack; Globaltest(BonStack);}Output:in Ctest2 in Bin GlobalTestCan't cast to C

static_cast 运算符

语法:

static_cast <type-id> (expression)

static_cast 通常用于数值类型转换,例如枚举和整型,整型和浮点类型的转换。

在标准 C++ 中,static_cast 转换没有运行时检测来保证安全性。在 C++/CX 中,则包含了编译和运行时检测。

static_cast 运算符能够用于将基类指针转换为派生类指针,但这样的转换不总是安全的。

下面还是通过示例进行讲解。

示例1:

class B {};class D : public B {};void f(B* pb, D* pd) { D* pd2 = static_cast<D*>(pb); // Not safe, D can have fields         // and methods that are not in B. B* pb2 = static_cast<B*>(pd); // Safe conversion, D always         // contains all of B.}

示例1 中 pd2 不为空,当用指针 pd2 调用 B 类型对象不存在的方法或者成员时可能会发生运行时错误(比如调用虚函数)或者返回非预期的值。

示例2:

typedef unsigned char BYTE;void f() { char ch; int i = 65; float f = 2.5; double dbl; ch = static_cast<char>(i); // int to char dbl = static_cast<double>(f); // float to double i = static_cast<BYTE>(ch);}

示例2 中 static_cast 运算符显示地将内置类型进行转换。

关于 static_cast 运算符,还有以下几种使用情况:

  • static_cast 能够显式的将整型转换为枚举类型。如果整型值不在枚举值范围内,那么返回的枚举值是未定义的。

  • static_cast 能将任何 expression 显式地转换为 void 类型。

  • static_cast 操作符不会去除 const,volatile,__unaligned 属性。

区分几种强制转换的使用场景

dynamic_cast 主要用于多态类型的强制转换,而 static_cast 主要用于非多态类型的强制转换。

static_cast 转换不像 dynamic_cast 那样安全。因为 static_cast 没有运行时检测。通过 dynamic_cast 进行转换时,一旦存在歧义,就会导致失败,然而 static_cast 会像没有错误发生一样返回结果。尽管 dynamic_cast 更加安全,但 dynamic_cast 仅适用于指针和引用,并且运行时检测是需要消耗性能的。

示例:

class B {public: virtual void Test(){}};class D : public B {};void f(B* pb) { D* pd1 = dynamic_cast<D*>(pb); D* pd2 = static_cast<D*>(pb);}

如果 pb 实际指向类型 D 或者 pd == 0,那么 pd1 和 pd2 将获得相同的值。

如果 pb 实际指向类型 B,那么 dynamic_cast 会返回 0。但是 static_cast 依赖于 expression 认定 pb 指向 D 类型对象,于是简单的返回 D 类型的指针。

结果就是,static_cast 转换会继续执行,但其返回结果是未定义的。这就需要调用者去进一步验证转换结果是有效的。

总结

到此,相信大家对“C++基础入门篇之强制转换讲解”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: C++基础入门篇之强制转换讲解

本文链接: https://www.lsjlt.com/news/249544.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++基础入门篇之强制转换讲解
    本篇内容主要讲解“C++基础入门篇之强制转换讲解”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++基础入门篇之强制转换讲解”吧!引言假设有基类 A,包含了虚函数 func1,以及有派生类 B,...
    99+
    2023-06-07
  • C++入门之模板基础讲解
    目录前言引入模板函数模板模板的匹配原则模板的显示调用类模板注意1注意2总结 前言 今天博主将要介绍的内容是–模板,他在C++中具有非常重要的位置.至于什么是模板呢?我们请看...
    99+
    2024-04-02
  • C++超详细讲解强制类型转换
    目录1 C 强制类型转换2 C++ 强制类型转转1 C 强制类型转换 C 方式的强制类型转换的用法如下代码所示: (Type)(Expression) Type:需要转换成的类型Ex...
    99+
    2024-04-02
  • springboot与springmvc基础入门讲解
    目录一,SpringBoot–1,概述–2,用法二,SpringMVC–1,概述–2,原理–3,入门案例总结一,SpringBoot –1,概述 用来整合maven项目,可以和Sp...
    99+
    2024-04-02
  • Python入门基础之import机制
    目录 一、前言 1.1 什么是 import 机制? 1.2 import 是如何执行的? 二、import 机制概览 三、import 勾子(import hooks) ...
    99+
    2024-04-02
  • C语言基础隐式类型转换与强制类型转换示例解析
    目录类型转换隐式类型转换强制类型转换类型转换 数据有不同的类型,不同类型数据之间进行混合运算时必然涉及到类型的转换问题。 转换包括隐式类型转换和强制类型转换。 类型转换的原则:占用内...
    99+
    2024-04-02
  • C++基础入门之运算符
    目录1. 算术运算符2. 赋值运算符3. 比较运算符4. 逻辑运算符总结 1. 算术运算符 2. 赋值运算符 3. 比较运算符 4. 逻辑运算符 总结 本篇文章就到这里了,希...
    99+
    2024-04-02
  • C语言入门之基础知识详解
    目录一、思维导图二、环境搭建三、编码规范四、基本数据类型五、分支循环5.1 分支5.2 循环六、break与continue6.1 无限循环一、思维导图 内容不限于此思维导图 二、...
    99+
    2024-04-02
  • 一篇文章带你了解C语言:入门基础
    目录C语言本身特点数据类型常量变量变量分类使用小建议生命周期作用域常量分类及其特点字符串+转义字符+注释字符串转义字符两种注释选择循环语句函数数组总结闲话少说,先上思维导图。 如图...
    99+
    2024-04-02
  • C++超详细讲解强制类型转换的用法
    目录static_castdynamic_castconst_castreinterpret_caststatic_cast static_cast<type-id>(e...
    99+
    2024-04-02
  • C++ 强制类型转换详解
    目录一、C强制转换二、C++强制转换1、static_cast 静态转换(编译时检查)2、const_cast 常量转换3、reinterpret_cast 重新解释转换4、dyna...
    99+
    2024-04-02
  • C语言入门篇--sizeof与strlen基础理论
    1.sizeof (1)若求字符串占据 空间 的大小,包括字符串结尾处默认的'\0'。 (2)若所求不是字符串的大小,求的是数组、类型等的大小,不用考虑'\0',因为不是字符串,在结...
    99+
    2024-04-02
  • Java基础入门篇之如何理解方法和重载
    本篇内容介绍了“Java基础入门篇之如何理解方法和重载”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、什么是方法简单来说方法就是一段可以被...
    99+
    2023-06-15
  • 一篇文章带你了解C语言:入门基础(2)
    目录操作符算术操作符移位操作符位操作符单目操作符逻辑反操作!操作符++,--逻辑操作符条件操作符逗号表达式常见关键字typedefexternstatic修饰局部变量修饰全局变量和函...
    99+
    2024-04-02
  • Java基础入门篇之如何使用For循环
    这篇文章主要讲解了“Java基础入门篇之如何使用For循环”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java基础入门篇之如何使用For循环”吧! 一、for循环语句在java中...
    99+
    2023-06-15
  • C#多线程学习之基础入门
    目录同步方式异步多线程方式异步多线程优化异步回调异步信号量异步多线程返回值异步多线程返回值回调线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进...
    99+
    2024-04-02
  • Java基础篇之反射机制详解
    目录1、反射概述1.1什么是反射1.2、反射能干什么2、解剖类2.1反射构造方法2.1.1反射无参的构造函数2.1.2反射“一个参数”的构造函数2.1.3反射...
    99+
    2024-04-02
  • html form表单基础入门案例讲解
    目录一,表格标签–1,概述–2,总结二,表单标签–1,测试–2,总结–3,form提交数据三,form表单的练习四,CSS-1,概述-2,语法-3,入门案例五,选择器总结一,表格标签...
    99+
    2024-04-02
  • JavaScript基础入门之错误捕获机制
    目录前言Error 对象throwtry…catch…finallyfinally 的规则Try / Catch 性能window.onerrorPromise 中的异常Promis...
    99+
    2024-04-02
  • 深入解析Java反射之基础篇
    目录前言一、回顾:什么是反射?二、反射的主要用途三、反射的基本运用1、获得 Class 对象2、判断是否为某个类的实例3、创建实例4、获取方法5、获取构造器信息6、获取类的成员变量(...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作