精华内容
下载资源
问答
  • 隐式转换
    2021-05-16 19:19:51

    三种隐式转换类型

    JS中一个难点就是隐式转换,因为JS在一些操作符下其类型会做一些变化,所以JS灵活,同时也会造成一些错误,并且难以理解

    这其中涉及隐式转换最多的两个运算符 + ==

    +运算符即可数字相加,也可以字符串相加,所以比较麻烦,== 不同于 ===,也存在隐式转换, */-这些操作符都是针对number类型的,故转换的结果只能是转换成number

    一个从类型 S 到类型 T 的隐式转换由一个函数类型 S => T 的隐式值来定义,或者由一个可转换成所需值的隐式方法来定义。

    隐式转换在两种情况下会用到:

    1.如果一个表达式 e 的类型为 S, 并且类型 S 不符合表达式的期望类型 T

    2.在一个类型为 S 的实例对象 e 中调用 e.m, 如果被调用的 m 并没有在类型 S 中声明。

    在第一种情况下,搜索转换 c,它适用于 e,并且结果类型为 T。 在第二种情况下,搜索转换 c,它适用于 e,其结果包含名为 m 的成员。

    如果一个隐式方法 List[A] => Ordered[List[A]],以及一个隐式方法 Int => Ordered[Int] 在上下文范围内,那么对下面两个类型为 List[Int] 的列表的操作是合法的:

         List(1, 2, 3) <= List(4, 5)

    在 scala.Predef.intWrapper 已经自动提供了一个隐式方法 Int => Ordered[Int]。下面提供了一个隐式方法 List[A] => Ordered[List[A]] 的例子

    import scala.language.implicitConversions implicit def list2ordered[A](x: List[A]) (implicit elem2ordered: A => Ordered[A]): Ordered[List[A]] = new Ordered[List[A]] { //replace with a more useful implementation def compare(that: List[A]): Int = 1 }

    自动导入的对象 scala.Predef 声明了几个预定义类型 (例如 Pair) 和方法 (例如 assert),同时也声明了一些隐式转换。

    例如,当调用一个接受 java.lang.Integer 作为参数的 Java 方法时,你完全可以传入一个 scala.Int。那是因为 Predef 包含了以下的隐式转换

    import scala.language.implicitConversions implicit def int2Integer(x: Int) = java.lang.Integer.valueOf(x)

    更多相关内容
  • 在本篇文章里小编给大家整理了关于C++隐式转换问题分析及解决办法,有需要的朋友们可以学习下。
  • 背景 在一次进行SQl查询时,我试着对where条件中vachar类型的字段去掉单引号查询,这个时候发现这条本应该很快的语句竟然很慢。这个varchar字段有一个复合索引。其中的总条数有58989,甚至不加单引号查出来的数据...
  • 写这篇文章的时候,还真不知道如何取名,也不知道这个该如何将其归类。这个是同事遇到的一个案例,案例比较复杂,这里抽丝剥茧,仅仅构造一个简单的案例来展现一下这个问题。我们先构造测试数据,如下所示: ...
  • 主要介绍了scala 隐式转换与隐式参数的使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 主要介绍了JavaScript中的一些隐式转换和总结,非常不错,具有参考借鉴价值,需要的朋友可以参考下
  • 工作过程中会遇到比较多关于隐式转换的案例,隐式转换除了会导致慢查询,还会导致数据不准。本文通过几个生产中遇到的案例来。 基础知识 关于比较运算的原则,MySQL官方文档的描述: ...
  • 本文通过实例代码给大家介绍了MySQL隐式转换问题,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
  • 在写这篇文章之前,让我们先回顾一下编译器通过匹配过程确定调用哪一个函数的匹配顺序:(1)寻找和使用最符合函数名和参数类型...C语言编译系统提供的内部数据类型的自动隐式转换规则如下:1.程序在执行算术运算时,
  • 编译器经常会背着我们做一些我们不希望发生的事情,典型的是隐式转换。不过庆幸的是,编译器只会帮助我们进行一次转换,而不会无休止的隐式转换,直至满足条件为止。例如,下面先定义一个Array模板类: template...
  • 本篇文章主要介绍了PHP中in_array的隐式转换的解决方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 该文档描述了oracle数据的转换的一些规则,如字符和数字的转换,字符和日期的转换
  • 笔记,csdn搜可以搜到,自己的总结。
  • sql隐式转换This article will provide an overview of SQL Server implicit conversion including data type precedence and conversion tables, implicit conversion examples and means to detect occurrences of...

    sql隐式转换

    This article will provide an overview of SQL Server implicit conversion including data type precedence and conversion tables, implicit conversion examples and means to detect occurrences of implicit conversion

    本文将概述SQL Server隐式转换,包括数据类型优先级和转换表,隐式转换示例以及检测隐式转换发生的方法

    SQL Server query performance issues are one of the most challenging processes for database administrators. In some cases, query performance can cause huge problems and it might affect the whole SQL Server instance performance. That is why every database administrator has some knowledge about query performance and troubleshooting methodologies.

    SQL Server查询性能问题是数据库管理员面临的最具挑战性的过程之一。 在某些情况下,查询性能可能会导致巨大的问题,并且可能会影响整个SQL Server实例的性能。 这就是为什么每个数据库管理员都具有有关查询性能和故障排除方法的一些知识的原因。

    Certainly, there are lots of factors and reasons which affect the query performance. However, the main principle or technique to solve these types of problems is based on well understanding and interpreting of the SQL execution plan of query. The SQL Execution plans show us series of steps which are taken during query execution, so we can uncover and find out any performance problems related to query. After all this brief information about query performance issues, we will discuss and learn the details of this kind of topic which affects query performance which is named as implicit conversion.

    当然,有很多因素和原因会影响查询性能。 但是,解决这类问题的主要原理或技术是基于对查询SQL执行计划的充分理解和解释。 SQL执行计划向我们展示了在查询执行过程中采取的一系列步骤,因此我们可以发现并发现与查询相关的任何性能问题。 在获得了有关查询性能问题的所有简短信息之后,我们将讨论并学习这种影响查询性能的主题的详细信息,该主题称为隐式转换。

    In some cases, we can combine two different data types in a join condition or we can compare two different data types in the where clause. In these cases, SQL Server tries to convert one data type to another during the query execution process. This data conversion process is referred to as Implicit Conversion because this type of conversion is made in behind of scenes by the SQL Server Query Optimizer and, as such, the process is abstracted from users. However, we can notice this type of conversion in the execution plan of the query.

    在某些情况下,我们可以在联接条件中组合两种不同的数据类型,也可以在where子句中比较两种不同的数据类型。 在这些情况下,SQL Server会在查询执行过程中尝试将一种数据类型转换为另一种数据类型。 此数据转换过程称为“隐式转换”,因为这种类型的转换是由SQL Server查询优化器在后台进行的,因此,该过程是从用户中抽象出来的。 但是,我们可以在查询的执行计划中注意到这种类型的转换。

    数据类型优先 (Data type precedence)

    Before we start discussing implicit conversion, we will review the concept of data type precedence in SQL Server. As we have already noted, the miss-matched data types have to be converted to compatible formats by SQL Server and this data type conversion is also done according to a defined process governed by precedence. The data type precedence rule specifies which data type is converted to the other. The data types have precedence order for SQL Server and the lower precedence data type is converted to the higher precedence data type.

    在开始讨论隐式转换之前,我们将回顾SQL Server中数据类型优先级的概念。 正如我们已经提到的,必须由SQL Server将未匹配的数据类型转换为兼容格式,并且此数据类型转换也要根据由优先级控制的已定义过程进行。 数据类型优先规则指定将哪种数据类型转换为另一种数据类型。 数据类型具有SQL Server的优先级顺序,较低优先级的数据类型将转换为较高优先级的数据类型。

    1. highest) 最高
    2. sql_variant

      sql_variant
    3. xml

      XML文件
    4. datetimeoffset

      日期时间偏移
    5. datetime2

      datetime2
    6. datetime

      约会时间
    7. smalldatetime

      小日期时间
    8. date

      日期
    9. time

      时间
    10. float

      浮动
    11. real

      真实
    12. decimal

      小数
    13. money

    14. smallmoney

      小钱
    15. bigint

      比金特
    16. int

      整型
    17. smallint

      Smallint
    18. tinyint

      tinyint
    19. bit

      一点
    20. ntext

      文字
    21. text

      文本
    22. image

      图片
    23. timestamp

      时间戳记
    24. uniqueidentifier

      唯一标识符
    25. nvarchar (including nvarchar(max) )

      nvarchar(包括nvarchar(max))
    26. nchar

      nchar
    27. varchar (including varchar(max) )

      varchar(包括varchar(max))
    28. char

      烧焦
    29. varbinary (including varbinary(max) )

      varbinary(包括varbinary(max))
    30. lowest) 最低

    例子 (Examples)

    In the following query, we will compare two columns which have different datatypes so we will prove the methodology of precedence data type conversion rule.

    在下面的查询中,我们将比较两个具有不同数据类型的列,以便证明优先数据类型转换规则的方法。

    In the first step, we will create a single column table and this column data type is integer and we will populate some data to this table.

    第一步,我们将创建一个单列表,并且此列的数据类型为整数,并将一些数据填充到该表中。

    DROP TABLE IF EXISTS TestPre
     
    CREATE TABLE TestPre
    (NumericCol INT)
     
    INSERT INTO TestPre 
    VALUES (1), (2), (3)
    

    Now, we will execute the following query and interpret the execution plan of this query and also don’t forget to activate actual execution plan before executing the query.

    现在,我们将执行以下查询并解释该查询的执行计划,并且不要忘记在执行查询之前激活实际的执行计划。

      SELECT * FROM TestPre WHERE NumericCol =N'1'
    

    As you can see the above image, the query optimizer converts the textual data type to an integer because INT data type precedence is higher than NVARCHAR.

    如上图所示,由于INT数据类型的优先级高于NVARCHAR,因此查询优化器将文本数据类型转换为整数。

    数据类型转换 (Data type conversion)

    The following summary conversion chart shows that which data type can be implicitly converted to another one.

    下面的摘要转换表显示可以将哪种数据类型隐式转换为另一种数据类型。

    转换限制 (Conversion limitations)

    However, according to this chart, all possible data conversions cannot be made by SQL Server such. When we look at the following sample, SQL Server does not convert textual data types to integers. The output of this query will be an error.

    但是,根据此图表,SQL Server无法进行所有可能的数据转换。 当我们看下面的示例时,SQL Server不会将文本数据类型转换为整数。 该查询的输出将是错误。

      SELECT * FROM TestPre WHERE NumericCol =N'A'
    

    In addition, if you require this type of conversion, you can use TRY_PARSE or TRY_CONVERT functions so that you can overcome this type of errors during the query execution.

    另外,如果您需要这种类型的转换,则可以使用TRY_PARSE或TRY_CONVERT函数,以便可以在查询执行期间克服此类错误。

    Note: You can find all details in the Ben Richardson’s Understanding SQL Server’s TRY_PARSE and TRY_CONVERT functions article.

    注意:您可以在Ben Richardson的《 了解SQL Server的TRY_PARSE和TRY_CONVERT函数》 文章中 找到所有详细信息

    检测隐式转换 (Detecting implicit conversions )

    Now, we will explore how to interpret execution plans which include implicit conversion. We will execute the following query in the Wide World Importers sample database and examine the actual execution plan.

    现在,我们将探讨如何解释包含隐式转换的执行计划。 我们将在Wide World Importers示例数据库中执行以下查询,并检查实际的执行计划。

    SELECT TransactionDate
         ,IsFinalized
      FROM [Sales].[CustomerTransactions]
    where IsFinalized LIKE '1%'
    

    As you can see in the above image, there is a warning sign in the select operator and it indicates that there is a problem in the execution plan. When we hover over the mouse icon in the Select operator, the detail screen will appear and we can find out the select operator details. The warning details clearly tell us the reason of the warning sign is implicit conversion. If we examine the detail of the execution plan, a wild card operator (%) is used for bit column and that is a problem because a bit column only takes two values and these are 1 (true) or 0 (false) so it does not make any sense to use ‘1%’ expression for bit column. When we go through the execution plan details, it makes the following conversion and this conversion purpose is convert textual data to bit data for this reason it takes the first character of the textual data.

    如上图所示,select运算符中有一个警告标志,它指示执行计划中存在问题。 当我们将鼠标悬停在“选择”运算符中的鼠标图标上时,将显示详细信息屏幕,我们可以找到“选择”运算符的详细信息。 警告详细信息清楚地告诉我们警告标志是隐式转换的原因。 如果我们检查执行计划的详细信息,则通配符运算符(%)用于位列,这是一个问题,因为位列仅包含两个值,并且它们是1(true)或0(false),所以它确实对于位列使用' 1% '表达式没有任何意义。 当我们仔细查看执行计划的详细信息时,它将进行以下转换,并且此转换目的是将文本数据转换为位数据,因此它采用了文本数据的第一个字符。

    CONVERT_IMPLICIT(varchar(1),[WideWorldImporters].[Sales].[CustomerTransactions].[IsFinalized],0)>='1'
    

    In addition, we are seeing another detail in the select operator which is about “CardinalityEstimate”. The task of Cardinality Estimator is to determine how many rows will be returned from the query and so this estimation directly affects the ability to choose the proper index. However, in this query, incorrect data type conversion directly affects the used index in the query.

    另外,我们在select运算符中看到了另一个有关“ CardinalityEstimate”的细节。 基数估计器的任务是确定将从查询返回多少行,因此该估计直接影响选择适当索引的能力。 但是,在此查询中,错误的数据类型转换将直接影响查询中使用的索引。

    Let’s avoid the implicit conversion for this query. The solution is very basic because we will only convert the “IsFinalized LIKE ‘1%’’” expression to “IsFinalized = 1” so that the query will return the same result set and we will avoid the implicit conversion affects in the query.

    让我们避免此查询的隐式转换。 该解决方案非常基础,因为我们将仅将“ IsFinalized LIKE'1%””表达式转换为“ IsFinalized = 1”,以便查询将返回相同的结果集,并避免查询中的隐式转换影响。

    SELECT TransactionDate
         ,IsFinalized
      FROM [Sales].[CustomerTransactions]
    where IsFinalized = 1
    

    As you can see in the above image, there isn’t any warning sign in the execution plan and also the index scan operator has changed the index seek operator. This index seek operator directly improves the query performance because the index seek operator is more selective than the index scan operator. At this point I want to add a notice about some details about implicit conversion. The conversion processes don’t change the query plan so they don’t affect query performance. Therefore, these type of data conversions are considered acceptable processes, in the context of managing performance.

    如上图所示,执行计划中没有任何警告标志,并且索引扫描运算符已更改了索引查找运算符。 该索引查找运算符直接改善了查询性能,因为索引查找运算符比索引扫描运算符更具选择性。 在这一点上,我想添加一个有关隐式转换的详细信息。 转换过程不会更改查询计划,因此不会影响查询性能。 因此,在管理性能方面,这些类型的数据转换被认为是可接受的过程。

    In addition, we can detect implicit conversion issues in our database by the help of Extended Events. The plan_affecting_convert event captures queries whose data type conversion does affect the query execution plan. Now, we will create a new extended event through the following script.

    此外,借助扩展事件,我们可以检测数据库中的隐式转换问题。 plan_affecting_convert事件捕获其数据类型转换确实会影响查询执行计划的查询。 现在,我们将通过以下脚本创建一个新的扩展事件。

    CREATE EVENT SESSION [ImplicitConversionCapture] ON SERVER 
    ADD EVENT sqlserver.plan_affecting_convert(
        ACTION(sqlserver.database_name)
        WHERE ([sqlserver].[database_name]=N'WideWorldImporters')),
    ADD EVENT sqlserver.sql_batch_completed(
        ACTION(sqlserver.database_name)
        WHERE ([sqlserver].[database_name]=N'WideWorldImporters')),
    ADD EVENT sqlserver.sql_batch_starting(
        ACTION(sqlserver.database_name)
        WHERE ([sqlserver].[database_name]=N'WideWorldImporters'))
    ADD TARGET package0.event_file(SET filename=N'ImplicitConversion')
    WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 
    SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
    GO
    

    We will start the extended event.

    我们将开始扩展活动。

    ALTER EVENT SESSION [ImplicitConversionCapture]  ON SERVER STATE= START
    

    In this step, we will re-execute the following query which causes implicit conversion and then analyze the data which is captured by our extended event.

    在这一步中,我们将重新执行以下查询,这将导致隐式转换,然后分析扩展事件捕获的数据。

    SELECT TransactionDate
         ,IsFinalized
      FROM [Sales].[CustomerTransactions]
    where IsFinalized  LIKE '1%'
    

    The above image shows that the plan_affecting_convert event occurred due to prior query which was executed.

    上图显示plan_affecting_convert事件是由于执行了先前的查询而发生的。

    Another option is DMVs (Dynamic Management Views) which is used to detect implicit conversion. Through the following query, we can detect the implicit conversion issued queries.

    另一个选项是DMV(动态管理视图),用于检测隐式转换。 通过以下查询,我们可以检测到隐式转换发出的查询。

    SELECT  DB_NAME(sql_text.[dbid]) AS DatabaseName,
    sql_text.text AS [Query Text],
    query_stats.execution_count AS [Execution Count], 
    execution_plan.query_plan AS [Query Plan]
    FROM sys.dm_exec_query_stats AS query_stats WITH (NOLOCK)
    CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS sql_text 
    CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS execution_plan
    WHERE 
    CAST(query_plan AS VARCHAR(MAX)) LIKE ('%CONVERT_IMPLICIT%')
    AND 
    DB_NAME(sql_text.[dbid])='WideWorldImporters'
    AND 
    CAST(query_plan AS VARCHAR(MAX)) NOT LIKE '%CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS sql_text%'
    

    结论 (Conclusion)

    In this article, we discussed implicit conversion details, related performance implications and also about how to detect related issues with help of extended events and dynamic management views.

    在本文中,我们讨论了隐式转换的详细信息,相关的性能含义以及有关如何借助扩展事件和动态管理视图检测相关问题的信息。

    翻译自: https://www.sqlshack.com/implicit-conversion-in-sql-server/

    sql隐式转换

    展开全文
  • C++类型转换:隐式转换和显式转换

    千次阅读 2020-12-30 20:07:09
    隐式转换 当一个值拷贝给另一个兼容类型的值时,隐式转换会自动进行。所谓隐式转换,是指不需要用户干预,编译器私下进行的类型转换行为。 例如: short a=2000; int b; b=a; 在这里,a在没有任何显示操作符的...

    目录

    隐式转换

    为什么要进行隐式转换

    C++隐式转换的原则

    C++隐式转换发生条件

    隐式转换的风险

    禁止隐式转换

    显式转换

    dynamic_cast

    static_cast

    const_cast

    reinterpret_cast


    隐式转换

    当一个值拷贝给另一个兼容类型的值时,隐式转换会自动进行。所谓隐式转换,是指不需要用户干预,编译器私下进行的类型转换行为。

    例如:

    short a=2000;
    int b;
    b=a;

    在这里,a在没有任何显示操作符的干预下,由short类型转换为int类型。这就是标准转换,标准转换将影响基本数据类型,并允许数字类型之间的转换(short到int, int到float, double到int…),到bool或从bool,以及一些指针转换。

    对于非基本类型,数组和函数隐式地转换为指针,并且指针允许如下转换:

    • NULL指针可以转换为任意类型指针
    • 任意类型的指针可以转换为void指针
    • 指针向上提升:一个派生类指针可以被转换为一个可访问的无歧义的基类指针,不会改变它的const或volatile属性

    为什么要进行隐式转换

    C++面向对象的多态特性,就是通过父类的类型实现对子类的封装。通过隐式转换,你可以直接将一个子类的对象使用父类的类型进行返回。再比如,数值和布尔类型的转换,整数和浮点数的转换等。某些方面来说,隐式转换给C++程序开发者带来了不小的便捷。C++是一门强类型语言,类型的检查是非常严格的。如果没有类型的隐式转换,这将给程序开发者带来很多的不便。

    C++隐式转换的原则

    • 基本数据类型 基本数据类型的转换以取值范围的作为转换基础(保证精度不丢失)。隐式转换发生在从小->大的转换中。比如从char转换为int。从int->long。
    •  自定义对象子类对象可以隐式的转换为父类对象。

    C++隐式转换发生条件

    • 混合类型的算术运算表达式中。例如:

      1

      2

      3

      int a = 3;

      double b = 4.5;

      a + b; // a将会被自动转换为double类型,转换的结果和b进行加法操作

    •  不同类型的赋值操作。例如:

      1

      2

      int a = true ; ( bool 类型被转换为 int 类型)

      int * ptr = null;(null被转换为 int *类型)

    •  函数参数传值。例如:

      1

      2

      void func( double a);

      func(1); // 1被隐式的转换为double类型1.0

    •  函数返回值。例如:

      1

      2

      3

      4

      double add( int a, int b)

      {

           return a + b;

      //运算的结果会被隐式的转换为double类型返回

    #以上四种情况下的隐式转换,都满足了一个基本原则:低精度 –> 高精度转换。不满足该原则,隐式转换是不能发生的。

    当然这个时候就可以使用与之相对于的显式类型转换(又称强制类型转换),使用方法如下:

           double a = 2.0;
           int b = (int)a;

         使用强制类型转换会导致精度的损失,因此使用时务必确保你已经拥有足够的把握。

    隐式转换的风险

    类的隐式转换:在类中,隐式转换可以被三个成员函数控制:

    • 单参数构造函数:允许隐式转换特定类型来初始化对象。
    • 赋值操作符:允许从特定类型的赋值进行隐式转换。
    • 类型转换操作符:允许隐式转换到特定类型

    参考文章

    隐式转换的风险一般存在于自定义的类构造函数中。

    按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象。

    #include <iostream>
    #include<cstdlib>
    #include<ctime>
     
    using namespace std;
    
    class Str
    {
    public:
    	// 用C风格的字符串p作为初始化值
    	Str(const char*p) {
    		cout << p << endl;
    	}
    	//本意是预先分配n个字节给字符串
    	Str(int n) {
    		cout << n << endl;
    	}
    
    };
    
    int main(void) {
    
    	Str s = "Hello";//隐式转换,等价于Str s = Str("Hello");
    
    	//下面两种写法比较正常:
    	Str s2(10);   //OK 分配10个字节的空字符串
    	Str s3 = Str(10); //OK 分配10个字节的空字符串
    
    	//下面两种写法就比较疑惑了:
    	Str s4 = 10; //编译通过,也是分配10个字节的空字符串
    	Str s5 = 'a'; //编译通过,分配int(‘a’)个字节的空字符串,使用的是Str(int n)构造函数
    	//s4 和s5 分别把一个int型和char型,隐式转换成了分配若干字节的空字符串,容易令人误解。
    	return 0;
    }
    /*
     *
    Hello
    10
    10
    10
    97
    */

    参考文章

    例二
    如下例:

    #include <iostream>
    #include<cstdlib>
    #include<ctime>
     
    using namespace std;
    class Test {
    public:
    	Test(int a):m_val(a) {}
    	bool isSame(Test other)
    	{
    		return m_val == other.m_val;
    	}
    private:
    		int m_val;
    };
    
    int main(void) {
    
    	Test a(10);
    	if (a.isSame(10)) //该语句将返回true
    	{
    		cout << "隐式转换" << endl;
    	}
    	return 0;
    }
    

    本来用于两个Test对象的比较,竟然和int类型相等了。这里就是由于发生了隐式转换,实际比较的是一个临时的Test对象。这个在程序中是绝对不能允许的。

    禁止隐式转换

    既然隐式转换存在这么多的风险,那如何能够禁止隐式转换的发生呢。C++中提供了explicit关键字,在构造函数声明的时候加上explicit关键字,能够禁止隐式转换。使用方法如下:

    class Test
    {
    explicit Test( int a);
    ……
     
    }
    #include <iostream>
    #include<cstdlib>
    #include<ctime>
     
    using namespace std;
    class Str
    {
    public:
    	// 用C风格的字符串p作为初始化值
    	explicit Str(const char*p) {
    		cout << p << endl;
    	}
    	//本意是预先分配n个字节给字符串
    	explicit  Str(int n) {
    		cout << n << endl;
    	}
    
    };
    class Test {
    public:
    	explicit Test(int a):m_val(a) {}
    	bool isSame(Test other)
    	{
    		return m_val == other.m_val;
    	}
    private:
    		int m_val;
    };
    
    int main(void) {
    
    	Test a(10);
    	if (a.isSame(10)) 编译不通过
    	{
    		cout << "隐式转换" << endl;
    	}
    
    	Str s = "Hello";//编译不通过
    
    //下面两种写法比较正常:
    	Str s2(10);   //OK 分配10个字节的空字符串
    	Str s3 = Str(10); //OK 分配10个字节的空字符串
    
    	//下面两种写法就比较疑惑了:
    	Str s4 = 10; //编译不通过
    	Str s5 = 'a'; //编译不通过
    	
    	return 0;
    }
    

    参考文章

    显式转换

    C++是一门强类型的语言,许多转换,特别是那些暗示值的不同解释的转换,需要显式转换,在c++中称为类型转换。泛型类型转换有两种主要语法:函数型和类c型:

    double x = 10.3;
    int y;
    y = int (x);    // functional notation
    y = (int) x;    // c-like cast notation 
    

    这些类型转换的通用形式的功能足以满足大多数基本数据类型的需求。但是,这些操作符可以不加区别地应用于类和指向类的指针上,这可能导致代码在语法正确的情况下导致运行时错误。编译器检查不出错误,可能导致运行时出错。例如,以下代码在编译时不会出现错误:

    // class type-casting
    #include <iostream>
    using namespace std;
    
    class Dummy {
    	double i, j;
    };
    
    class Addition {
    	int x, y;
    public:
    	Addition(int a, int b) { x = a; y = b; }
    	int result() { return x + y; }
    };
    
    int main() {
    	//情况一,通过强制类型转换,不同类型的指针可以随意转换,编译器不报错
    	Dummy d;
    	Addition * padd;
    	padd = (Addition*)&d;
    	cout << padd->result()<<endl;//Dummy 类中没有result,但是编译器不报错
    
    	//情况二:将指向const对象的指针转成指向非const
    	int a = 666;
    	const int *p1 = &a;
    	//*p1 = 999;//这里会报错,p指向的值为常量,不能赋值更改
    	int *p2 = (int *)p1;
    	*p2 = 999;//经过强制类型转换后,失去了const属性,此时不报错
    	cout <<"a = "<< a << endl;//a 的值已被更改了
    	return 0;
    }

    程序声明了一个指向Addition的指针,但随后使用显式类型转换将另一个不相关类型对象的引用赋给该指针:

    padd = (Addition*) &d;

    不受限制的显式类型转换允许将任何指针转换为任何其他指针类型,而不依赖于指针所指向的类型。后面成员函数result的调用将产生运行时错误或其他一些意外结果。

    其他情况:

    • 将指向const对象的指针转换成非const对象的指针
    • 可能将基类对象指针转成了派生类对象的指针

     总结:编译时报错优于运行时报错,所以C++引入的四种类型转换,不同场景下不同需求使用不同的类型转换方式,同时有利于代码审查。

    • static_cast
    • const_cast
    • dynamic_cast
    • reinterpret_cast
    dynamic_cast <new_type> (expression)
    reinterpret_cast <new_type> (expression)
    static_cast <new_type> (expression)
    const_cast <new_type> (expression)

    dynamic_cast

    dynamic_cast只能用于指向类的指针和引用(或void*)。它的目的是确保类型转换的结果指向目标指针类型的有效完整对象。

    将dynamic_cast用于引用时,其用法稍有不同:没有与空指针对应的引用值,也就是说没有空引用,引用必须要初始化,因此无法使用特殊的引用值来指示失败,当请求不正确时,dynamic_cast将引发bad_cast异常。

    向上转换:将指向派生类的指针转为指向基类的指针,其方式与隐式转换相同。

    向下转换:将指向基类的指针转为指向派生类的指针,此时的类需要是多态类(具有虚成员的类)

    #include <iostream>
    
    using namespace std;
    
    struct Base {
        virtual void Func() { cout << "Base Func \n"; }
    };
    
    struct Derive : public Base {
        void Func() override { cout << "Derive Func \n"; }
    };
    
    int main() {
        Derive d;
        d.Func();
        Base *b = dynamic_cast<Base *>(&d);
        b->Func();
        Derive *dd = dynamic_cast<Derive *>(b);
        dd->Func();
        return 0;
    }

    // dynamic_cast
    #include <iostream>
    #include <exception>
    using namespace std;
    
    class Base {
    public:
    	virtual void show() {
    	cout << "我是基类" << endl;
    } };
    class Derived : public Base { 
    	int a; 
    public:
    	void show() {
    		cout << "我是派生类" << endl;
    	}
    };
    
    int main() {
    	try {
    		Base * pba = new Derived;//这里做了隐式转换,将指向派生类的指针转为基类指针
    		Base * pbb = new Base;
    		Derived * pd;
    		Base *pb1, *pb2;
    
    		//向下转换,基类指针转为派生类指针,不过有条件,这个基类指针指向的对象原本就是派生类对象
    		pd = dynamic_cast<Derived*>(pba); //如果基类不是多态类型(无虚函数),则不能用dynamic_cast()向下转换
    		if (pd == 0) cout << "Null pointer on first type-cast.\n";
    		pd->show();
    
    		//如果基类指针指向的是基类对象,则不能转换为派生类指针,返回空指针
    		pd = dynamic_cast<Derived*>(pbb);
    		if (pd == 0) cout << "Null pointer on second type-cast.\n";
    
    		Derived *pd2 = new Derived;
    		//向上转换,将派生类指针转为基类指针
    		pb1 = pd2; //可以隐式转换
    		pb1->show();//如果show是虚函数,将会打印我是派生类,声明了虚函数之后,它是看内存中的对象,而不是指针类型
    		pb2 = dynamic_cast<Derived*>(pd2);//也可以显示转换
    		pb2->show();
    		
    
    	}
    	catch (exception& e) { cout << "Exception: " << e.what(); }
    	return 0;
    }
    /*
     *
    我是派生类
    Null pointer on second type-cast.
    我是派生类
    我是派生类*/

     使用场景:用于将父类的指针或引用转换为子类的指针或引用,此场景下父类必须要有虚函数,因为dynamic_cast是运行时检查,检查需要运行时信息RTTI,而RTTI存储在虚函数表中.

    static_cast

    static_cast可以在类相关的指针中完成转换,不仅是向上转换,还有向下转换。在运行时期间不执行任何检查,以确保正在转换的对象实际上是目标类型的完整对象。因此它依靠编译器确保转换是否安全,另一方面,它没有dynamic_cast运行时检查的开销。

    // dynamic_cast
    #include <iostream>
    #include <exception>
    using namespace std;
    
    class Base {
    public:
    	virtual void show() {
    	cout << "我是基类" << endl;
    } };
    class Derived : public Base { 
    	int a; 
    public:
    	void show() {
    		cout << "我是派生类" << endl;
    	}
    };
    
    int main() {
    	try {
    		Base * a = new Base;
    		Derived * b = static_cast<Derived*>(a);
    		b->show(); //如果show为虚函数,则显示我是基类,不是虚函数则显示我是派生类
    
    	}
    	catch (exception& e) { cout << "Exception: " << e.what(); }
    	return 0;
    }
    

     上面的代码可以编译通过,但很明显b指向的是一个不完整的对象,很可能在运行时发生错误。

    使用场景:基本数据类型之间的转换使用,例如float转int,int转char等,在有类型指针和void*之间转换使用,子类对象指针转换成父类对象指针也可以使用static_cast。

    非多态类型转换一般都使用static_cast,而且最好把所有的隐式类型转换都是用static_cast进行显示替换,不能使用static_cast在有类型指针之间进行类型转换。

    const_cast

    这种类型的类型转换操作指针所指向的对象的常量,可以是要设置的,也可以是要删除的。例如,为了将const指针传递给需要非const实参的函数:

    // const_cast
    #include <iostream>
    using namespace std;
    
    void print (char * str)
    {
      cout << str << '\n';
    }
    
    int main () {
      const char * c = "sample text";
      print ( const_cast<char *> (c) );
      return 0;
    }

     上面的例子保证可以工作,因为函数print不会写指向的对象。但是请注意,移除指向对象的常量以实际写入它会导致未定义的行为。

    int main() {
        int data = 10;
        const int *cpi = &data;
    
        int *pi = const_cast<int *>(cpi);
    
        const int *cpii = const_cast<const int *>(pi);
        return 0;
    }

     使用场景:用于常量指针或引用与非常量指针或引用之间的转换,只有const_cast才可以对常量进行操作,一般都是用它来去除常量性,去除常量性是危险操作,还是要谨慎操作。

    reinterpret_cast

     reinterpret_cast可以将指针类型任意转换,甚至是不相关的类之间,

    int main() {
        int data = 10;
        int *pi = &data;
    
        float *fpi = reinterpret_cast<float *>(pi);
    
        return 0;
    }

    使用场景:没啥场景,类似C语言中的强制类型转换,什么都可以转,万不得已不要使用,一般前三种转换方式不能解决问题了使用这种强制类型转换方式。操作结果是从一个指针到另一个指针的值的简单二进制拷贝

    允许所有的指针转换:既不检查指针所指向的内容,也不检查指针类型本身。

    可以由reinterpret_cast执行但不能由static_cast执行的转换是基于重新解释类型的二进制表示的低级操作,在大多数情况下,这将导致特定于系统的代码,因此不可移植。

    class A { /* ... */ };
    class B { /* ... */ };
    A * a = new A;
    B * b = reinterpret_cast<B*>(a);
    

     这段代码可以编译,尽管它没有多大意义,因为现在b指向一个完全不相关且可能不兼容的类的对象。解引用b是不安全的。

    它还可以强制转换指向或来自整数类型的指针。这个整数值表示指针的格式与平台有关。唯一的保证是,将指针转换为足够大的整数类型以完全包含它(如intptr_t),保证能够将其转换回有效的指针。

    Type conversions - C++ Tutorials

    C++为什么非要引入那几种类型转换?

    展开全文
  • 文章目录概述隐式转换使用步骤 概述 隐式转换和隐式参数是Scala中非常有特色的功能,也是Java等其它编程语言没有的功能。我们可以很方便的利用隐式转换来丰富现有类的功能。在编写Akka并发编程,Spark,Flink程序时...


    概述

    隐式转换和隐式参数是Scala中非常有特色的功能,也是Java等其它编程语言没有的功能。我们可以很方便的利用隐式转换来丰富现有类的功能。在编写Akka并发编程,Spark,Flink程序时都会经常用到它们。

    • 隐式转换:指的是用 implicit 关键字,声明的带有单个参数的方法。
    • 隐式参数:指的是用 implicit 关键字修饰的变量。

    注意:implicit 关键字是在 Scala 的 2.10版本出现的。


    隐式转换

    所谓隐式转换,是指以 implicit 关键字声明的带有单个参数的方法。该方法是被 自动调用 的。用来实现 自动将某种类型的数据转换为另外一种类型的数据。

    使用注意事项

    1. object单例对象 中定义隐式转换方法.

      隐式转换方法解释: 就是用implicit关键字修饰的方法.

    2. 在需要用到隐式转换的地方, 引入隐式转换.

      类似于 导包 , 通过 import关键字实现 .

    3. 当需要用到 隐式转换方法 时, 程序会自动调用

    4. 隐式转换函数的函数名可以是任意的,隐式转换与函数名无关,只与函数签名(函数参数类型和返回值类型有关。

    5. 隐式函数可以有多个(即:隐式函数列表),但是需要保证在当前环境下,只有一个隐式函数能被识别

    代码演示:

    object ImplicitDemo01 {
    
      def main(args: Array[String]): Unit = {
        //编写一个隐式函数转成 Double->Int 转换,隐式函数应当在作用域才能生效、
        implicit def f1(d: Double):Int = {  //底层生成 f1$1
          d.toInt
        }
    
        implicit def f2(f: Float):Int = {
          f.toInt
        }
    
        //这里必须保证隐式函数的匹配只能是唯一的
    //    implicit def f3(f1: Float):Int = {
    //      f1.toInt
    //    }
    
        val num: Int = 3.5  //底层编译 f1$(3.5) //idea_
        println("num = " + num)
        val num2: Int = 4.5f
        println("num2 = " + num)
      }
    
    }
    
    num = 3
    num2 = 3
    
    Process finished with exit code 0
    

    隐式值

    隐式值也叫隐式变量,将某个形参变量标记为 implicit,所以编译器会在方发省略隐式参数的情况下去搜索作用域内的隐式值作为缺省参数。

    代码:

    object 隐式值 {
    
      def main(args: Array[String]): Unit = {
        implicit val str1: String = "jack~"  //银式值
    
        //implicit name: String   //name就是隐式值
        def hello(implicit name: String):Unit = {
          println(name + "hello")
        }
    
        hello //底层 hello$1(str1)
      }
    
    }
    
    jack~hello
    
    Process finished with exit code 0
    

    隐式值,默认值,传值 优先级比较

    1. 当在程序中,同时有 隐式值,默认值,传值
    2. 编译器的优先级为:传值 > 隐式值 > 默认值
    3. 在隐式值匹配时,不能有二义性
    4. 如果三个(隐式值,默认值,传值) 一个都没有,就会报错

    代码演示:

    object 隐式值案例 {
    
      def main(args: Array[String]): Unit = {
        //隐式变量(值)
        //implicit val name: String = "Scala"
        implicit val name1: String = "World"
    
        //隐式参数
        def hello(implicit content: String="jack"): Unit = {
          println("Hello" + content)
        } //调用 hello
        hello //使用隐式值不要带()
    
        //当同时有 implicit值和默认值,implicit优先级高
        def hello2(implicit content: String = "jack"): Unit = {
          println("Hello2" + content)
        } //调用 hello
        hello2
    
        //说明
        //1. 当一个隐式参数匹配不到隐式值,仍然会使用默认值
        implicit val name: Int = 10
        def hello3(implicit content: String = "jack"): Unit = {
          println("Hello3" + content)
        } //调用hello
        hello3  //hello3 jack
    
        //当没有隐式值,没有默认值,又没有传值,就会报错
        def hello4(implicit content: String): Unit = {
          println("Hello4" + content)
        } //调用hello
        hello4  //hello3 jack
      }
    
    }
    
    HelloWorld
    Hello2World
    Hello3World
    Hello4World
    
    Process finished with exit code 0
    

    隐式类

    1. 隐式类所带的构造参数有且只能有一个
    2. 隐式类必须被定义在 “类” 或 “伴生对象” 或 “包对象” 里,即隐式类不能是顶级的(要考虑到作用域的问题)
    3. 隐式类不能是 case class(样例类)。
    4. 作用域内不能有与之相同名称的标识符。

    代码演示:

    object 隐式类 {
    
      def main(args: Array[String]): Unit = {
        /*DB1 会对应生成隐式类
          DB1 是一个隐式类,当我们在改隐式类的作用域范围,创建MySQL1实例
          该隐式类就会生效,这个工作仍然是编译器完成
        */
        implicit class DB1(val m: MySQL1) { //隐式类$DB1$2
          def addSuffix():String = {
            m + "scala"
          }
        }
    
        //创建一个MySQL1实例
        val mySQL = new MySQL1
        mySQL.sayOK()
        mySQL.addSuffix()
      }
    }
    
    class DB1 {}
    
    class MySQL1 {
      def sayOK(): Unit = {
        println("sayOK")
      }
    }
    
    sayOK
    
    Process finished with exit code 0
    

    如上代码,当实例化MySQL1类的时候,就会发生隐式转换,该隐式类就会生效。


    隐式转换时机

    1. 当方发中的参数类型与目标类型不一致时,或者是赋值时,会发生隐式转换。如下代码所示。
      在这里插入图片描述
    2. 当对象调用所在类中不存在的方发或成员时,编译器会自动将对象进行隐式转换(根据类型)。

    隐式解析机制

    编译器是如何查找到缺失信息的,解析具有以下俩种规则:

    • 1.首先会在当前代码作用域下查找隐式实体(隐式方发、隐式类、隐式对象)
    • 2.如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。类型的作用域是指与该类型相关联的全部伴生模块,一个隐式实体的类型T它的查找范围如下(第二种情况范围广且复杂在使用时,应当尽量避免出现)
      • (1) 如果T被定义为 T with A with B with C,那么A,B,C都是T的部分,它们的伴生对象都会被搜索。
      • (2) 如果T是参数化类型,那么类型参数和类型参数想关联的部分都算作T的部分,比如 List[String] 的隐式搜索会搜索 List 的伴生对象和 String 的伴生对象。
      • (3) 如果T是一个单例类型 p.T,即T是属于某个p对象内,那么这个p对象也会被搜索。
      • (4) 如果T是个类型注入S#T,那么S和T都会被搜索。

    隐式转换使用规则

    1. 不能存在二义性。
    2. 隐式操作不能嵌套使用。

    在这里插入图片描述

    展开全文
  • 显式转换# 首先对要转换的数据进行变量的声明float_number = 1.5int_number = 2# 其他类型转换到字符串,使用的是str()函数# 浮点数转字符串float_to_str = str(float_number)#打印结果print(float_to_str)# 检查...
  • JavaScript数据类型隐式转换 引言——面试题 在讲JavaScript的数据类型隐式转换前,我们先看道面试题: console.log(new String('abc') == true) console.log({} == true) console.log([] == ![]) 结果是什么呢?...
  • JavaScript的隐式转换

    2021-06-04 20:48:03
    JavaScript的隐式转换一、 JavaScript 数据类型二、 JavaScript 隐式转换1. 隐式转换规则1. + 运算符2. == 运算符3. >运算符4.复杂数据类型 一、 JavaScript 数据类型 js中有7种数据类型,可以分为两类:原始类型...
  • Spark隐式转换

    2021-05-25 11:50:09
    隐式转换开荒2.1 隐式转换函数 参数RichFile2.2 隐式类2.3 隐式解析机制三.回归主题 一. 生产问题背景 如上就是此blog产生的背景, Spark SQL 中, DF.select() select 报错 不能导入 spark sql Cannot resolve...
  • js中的隐式转换与强制转换 JavaScript 是一种动态类型的语言,在执行运算操作的过程中,有时需要转换操作数的类型。在 JavaScript 中,数据类型的转换有:隐式类型转换和强制类型转换(也叫显式类型转换)两种方式。...
  • 用户定义的转换必须是转换成封闭类型,或者从封闭类型转换 参考 其他 应用和设计 读音 参考 前言 有时我们会遇到这么一种情况:在json数据里,数组里的数据类型不一致,导致我们不能直接反序
  • 1、js数据类型 ...Undefined、Null的特殊情况以及Boolean的转换都比较好记忆。剩下的只需要关注好 String、Number 这两种类型。 1种对象类型: Object 2、类型转换 数据类型间的转换可分为: 原始值间的转换
  • 1、隐式转换(implicit)----给对象动态的增加方法 当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译 隐式转换可以在不需改任何代码的情况下,扩展...
  • MySQL隐式转换

    2021-11-13 22:53:40
    当我们对不同类型的值进行比较的时候,为了使得这些数值「可比较」(也可以称为类型的兼容性),MySQL会做一些隐式转化(Implicit type conversion)。 若字符串是以数字开头,且全部都是数字,则转换为数字结果是...
  • 1.隐式转换 1.1 知识点 1.2 练习题 2.显式转换 2.1 知识点 2.2 练习题 前言 视频资料来源于bilibili 唐老狮 1.隐式转换 1.1 知识点 namespace lesson7_隐式转换 { class Program { static void Main...
  • scala中隐式转换

    2022-01-03 16:19:02
    scala中默认的情况下支持数值类型的自动转换 byte->short->int->long scala默认情况下支语法中的类型的...隐式函数可以有多个,但是需要保证当前环境下只有一个隐式转换函数能够被识别 隐式值 隐式值也叫隐

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 233,658
精华内容 93,463
关键字:

隐式转换

友情链接: 微端服务器.rar