精华内容
下载资源
问答
  • 隐式转换和显式转换
    千次阅读
    2020-11-28 12:11:01

    前言:

    转载请附上连接,本帖原创请勿照抄。

    文章开头先引用一个概念,隐式转换,那么隐式转换和显式转换的区别:

        例如,一个int类型的变量转换QString的时候,QStringList qStrList;  QString qStr=qStrList;  直接就可以转换中间不需要通过其他转换直接就可以实现功能。

        比如一个Byet需要转换为QString的时候,可能要转换成其他类型的变量再转才能转换为QString,这就是显式转换。

        这只是举个例子,转换方式不对请勿介意看看就好,就是说一个概念。隐式转换将过程屏蔽了直接就可以转换,显式则需要自己一步一步转换。

    Qt中许多常用的类都使用了隐式共享技术,如QString、QImage、容器类、绘图相关类等等。

     	
    QString str1 = "ubuntu";
    QString str2 = str1;        //str2 = "ubuntu"
    str2[2] = "m";              //str2 = "ubmntu",str1 = "ubuntu"
    str2[0] = "o";              //str2 = "obmntu",str1 = "ubuntu"
    str1 = str2;                //str1 = "obmntu",

    解释:

    line1: 初始化一个内容为"ubuntu"的字符串;
    line2: 将字符串对象str1赋值给另外一个字符串str2(由QString的拷贝构造函数完成str2的初始化)。
    在对str2赋值的时候,会发生一次浅拷贝,导致两个QString对象都会指向同一个数据结构。该数据结构除了保存字符串“ubuntu”之外,还保存一个引用计数器,用来记录字符串数据的引用次数。此处,str1和str2都指向同一数据结构,所以此时引用计数器的值为2.
    line3: 对str2做修改,将会导致一次深拷贝,使得对象str2指向一个新的、不同于str1所指的数据结构(该数据结构中引用计数器值为1,只有str2是指向该结构的),同时修改原来的、str1所指向的数据结构,设置它的引用计数器值为1(此时只有str1对象指向该结构);并在这个str2所指向的、新的数据结构上完成数据的修改。引用计数为1就意味着该数据没有被共享。
    line4: 进一步对str2做修改,不过不会引起任何形式的拷贝,因为str2所指向的数据结构没有被共享。
    line5: 将str2赋给str1.此时,str1修改它指向的数据结构的引用计数器的值位0,表示没有QString类的对象再使用这个数据结构了;因此str1指向的数据结构将会从从内存中释放掉;这一步操作的结构是QString对象str1和str2都指向了字符串为“obmntu”的数据结构,该结构的引用计数为2。

     

     

     

     

     

    更多相关内容
  • 本文介绍下C#中的类型转换,以及如何自定义隐式转换和显式转换

    来源:https://note.guoqianfan.com/2022/04/22/operator-implicit-explicit-in-csharp/

    前言

    有时我们会遇到这么一种情况:在json数据里,数组里的数据类型不一致,导致我们不能直接反序列化为目标类型。最终我们只能反序列化为JObject类型,然后通过字符串取值的方式来取出数据。

    下面介绍一种新方式:通过自定义隐式转换,把不一样的数据类型反序列化为一样的数据类型。

    基础知识

    类型转换有2种:隐式转换和显式转换。但是,不管是隐式转换,还是显式转换,都是生成了一个新对象返回的。改变新对象的属性,不会影响老对象!(dynamic对象除外,详情搜索dynamic动态类型)

    自定义隐式/显式转换的方法需要用到几个关键字:implicit(隐式转换)、explicit(显式转换)、operator(操作符)。更多的注意点见下:

    1. 方法必須是static
    2. 使用implicitexplicit
    3. 搭配operator(此也是c#關鍵字,可在類別或結構宣告內多載內建運算子或提供使用者定義的轉換)
    4. 返回值为要转换为的目标类型,但不要在方法上声明,方法名目标类型。注意:返回值不一定是本类类型。本类型和其他类型之间可以互相转换,只要定义转换方法就行。
    5. 参数为原始类型,方法名目标类型
    6. 类A到类B的类型转换定义不能在类C中进行(即2个类的转换不能在第3个类中定义),否则会报错:用户定义的转换必须是转换成封闭类型,或者从封闭类型转换。具体查看后面的用户定义的转换必须是转换成封闭类型,或者从封闭类型转换
    7. 不能被virtual/override修饰(不能“覆盖”运算符,因为它们是静态的。)Overriding implicit operators in C#

    示例代码

    //================定义类型和方法================
    class Robot
    {
        public int Id { get; set; }
        public string Name { get; set; }
    
        public Robot(int id, string name)
        {
            Id = id;
            Name = name;
        }
    
        #region 其他类型->本类
    
        //隐式转换
        public static implicit operator Robot(string name)
        {
            return new Robot(101, name);
        }
    
        //显式转换
        public static explicit operator Robot(int id)
        {
            return new Robot(id, "miku");
        }
    
        #endregion
    
        #region 本类->其他类型
    
        //隐式转换
        public static implicit operator string(Robot robot)
        {
            return robot.Name;
        }
    
        //显式转换
        public static explicit operator int(Robot robot)
        {
            return robot.Id;
        }
    
        #endregion
    }
    
    //================测试代码================
    #region 其他类型->本类
    
    string gumiStr = "gumi";
    Robot gumi001 = gumiStr; //隐式转换
    Console.WriteLine("隐式转换:gumi001 : {0}", JsonConvert.SerializeObject(gumi001));
    
    int lukaId = 1004;
    Robot luka001 = (Robot)lukaId; //显式转换
    Console.WriteLine("显式转换:luka001 : {0}", JsonConvert.SerializeObject(luka001));
    
    #endregion
    
    #region 其他类型->本类
    
    Robot miku001 = new Robot(1001, "miku10001");
    //隐式转换
    string mikuName = miku001;
    //显式转换
    int mikuId = (int)miku001;
    
    Console.WriteLine("隐式转换:miku001 Name: {0}", mikuName);
    Console.WriteLine("显式转换:miku001 Id: {0}", mikuId);
    
    #endregion
    

    输出结果如下:

    隐式转换:gumi001 : {"Id":101,"Name":"gumi"}
    显式转换:luka001 : {"Id":1004,"Name":"miku"}
    隐式转换:miku001 Name: miku10001
    显式转换:miku001 Id: 1001
    

    实际应用

    问题

    [1,[[2,2],[2,2],[2,2],[2,2]]]

    这样一个字符串,如何可以反序列化成一个对象?(如何定义这个类?)

    答案

    using System;
    using System.Linq;
    using System.Collections.Generic;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
                        
    public class Program
    {
        public static void Main()
        {
            var json = "[1,[[2,2],[2,2],[2,2],[2,2]]]";
            var root = JsonConvert.DeserializeObject<Root>(json);
            foreach(var ele in root)
            {
                if(ele.SingleValue.HasValue)
                {//有值,原始数据为 1
                    Console.WriteLine(ele.SingleValue.Value);
                }else
                {//原始数据为 二维数组
                    Console.WriteLine(string.Join(" ",ele.Select(x=>string.Join(",",x))));
                }
            }
            Console.WriteLine(JsonConvert.SerializeObject(root));
        }
    }
    
    class Root : List<Element> { }
    [JsonConverter(typeof(CConverter))]
    class Element : List<List<long>>
    {
        //该属性,存放 1 。后续可以通过判断该属性是否有值来得知原始数据的情况
        public long? SingleValue { get; set; }
    
        //遇到 1 ,隐式转换为 该类型,其中 1 被存放到SingleValue属性
        public static implicit operator Element(long d)
        {
            return new Element { SingleValue = d };
        }
    }
    
    public class CConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(Element));
        }
    
        public override bool CanRead  { get { return false; } }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var ele = value as Element;
            var token = ele.SingleValue.HasValue ? JToken.FromObject(ele.SingleValue.Value) : JToken.FromObject(ele.ToList());
            token.WriteTo(writer);
        }
    
        public override bool CanWrite { get { return true; } }
    }
    

    报错

    用户定义的转换必须是转换成封闭类型,或者从封闭类型转换

    这个错误,与封闭类型无关

    是因为有这个限制:类A到类B的类型转换定义不能在类C中进行(即2个类的转换不能在第3个类中定义)

    所以对于目标类型是集合类List<T>,我们无法直接定义到它的转换。不过,有2个迂回的方法:

    • 创建个类继承自集合类List<T>,定义到这个子类的转换。上面实际应用中的代码就是这样做的:class Element : List<List<long>>
    • 创建T1T2的自定义转换,使用时逐个转换:list.Select(p=>(B)p).ToList()

    参考

    1. 隐式转换:用户定义的转换必须是转换成封闭类型,或者从封闭类型转换:https://blog.csdn.net/kamui_shiron/article/details/8807142

    其他

    应用和设计

    在定義類別時,如果有需要,就可以使用這兩個關鍵字來提供類別一些額外的功能

    但在使用時也必須考慮設計上是否合理

    例如當兩類別有相關性時是否該提取出父类或是接口來使用,而不是為了方便做了一堆轉換,導致程式撰寫與維護上的困難。

    读音

    • 隐式转换:implicit [ɪmˈplɪsɪt] adj.不言明[含蓄]的; 无疑问的,绝对的; 成为一部份的; 内含的;
    • 显式转换:explicit [ɪkˈsplɪsɪt] adj.明确的,清楚的; 直言的; 详述的; 不隐瞒的;

    参考

    1. 【问】这样一个字符串如何反序列化:http://www.newsmth.net/nForum/#!article/DotNET/69817
    2. 型別轉換關鍵字explicit與implicit的用法:https://dotblogs.com.tw/lastsecret/2011/11/14/57875
    3. c#关键词implicit和explicit:https://blog.csdn.net/Joyhen/article/details/40110391
    展开全文
  • 一、 隐式转换也叫自动类型转换,指的是不需要调用函数,JVM自动将类型转换的一种方式。因为这种类型转换经常使用,Java语言在设计时,为了减轻开发人员的负担,都交给JVM来自动处理。 1)转换规则从存储范围小的...

           一、 隐式转换也叫自动类型转换,指的是不需要调用函数,JVM自动将类型转换的一种方式。因为这种类型转换经常使用,Java语言在设计时,为了减轻开发人员的负担,都交给JVM来自动处理。

               1)转换规则从存储范围小的类型到存储范围大的类型(只有前面的数据才能随便转换为后边的)

               byte—> short,char—> int —> long—> float —> double

              2) 例子:

              byte b = 2; short s = b; 首先JVM会将b的值转换为short类型,再将值赋值给s

           二、显示转换也叫强制类型转换,指的是需要手动去处理才能完成的类型转换。该转换会存在精度损失。

             1)转换规则从存储范围大的类型到存储范围小的类型

               double→float→long→int→short(char)→byte

            2)例子:

           double d = 1.1; int i = (int)d;首先将d的值转换成int类型,然后赋值给变量i。需要注意的是小数强制转换为整数,采用的是“去1法”,也就是舍弃小数点后面所有数字,则以上转换出的结果是1。整数强制转换为整数时取数字的低位,例如int类型的变量转换为byte类型时,则只去int类型的低8位(也就是最后一个字节)的值。

           三、常见面试题

    short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 +=1;有什么错?

     答:对于short s1=1;s1=s1+1;来说,在s1+1运算时会自动转换类型为int,那么将int类型赋给short类型的变量s1会出现类型转换错误。

     对于short s1=1;s1+=1来说 +=是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。

     

    展开全文
  • 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++为什么非要引入那几种类型转换?

    展开全文
  • 2.显式转换 2.1 知识点 2.2 练习题 前言 视频资料来源于bilibili 唐老狮 1.隐式转换 1.1 知识点 namespace lesson7_隐式转换 { class Program { static void Main(string[] args) { #region 类型转换...
  • C++类型的隐式转换和显式转换

    千次阅读 2017-06-27 19:40:18
    隐式转换:编译器根据需要自动转换变量类型。 1、一些基本类型的转换 double d = 82.0; int i = d; 2、类的隐式转换,以下几种情况,类B能隐式转换成类A: (1)B公有继承A,然后用子类去初始化基类 class A{}; ...
  • 数据类型-转换-隐式转换和显式转换

    千次阅读 热门讨论 2021-01-05 10:00:16
    数据类型转换分为隐式转换和显式转换,根据不同的转换对象,来确定是那种类型的转换。 隐式转换:就是系统默认的、不需要加以声明就可以进行转换。 首先来说在程序语言中默认的类型,一般整数是int类型 ,浮点数...
  • systemverilog中隐式转换和显示转换(动态转化和静态转换) 显式转换包含动态转换和静态转换 动态转换:例如 unsigned’(signed_vec) 静态转换:例如 $cast(target, source) 这两种转换均需要操作符号和系统函数介入...
  • C语言数据类型转换、隐式类型转换、显式类型转换、强制类型转换、隐式转换显式转换、强制转换
  • C++: 隐式类型转换和显式类型转换

    千次阅读 2019-11-06 12:49:44
    隐式类型转换 又称为“标准转换”,包括以下几种情况: 1) 算术转换(Arithmetic conversion) : 在混合类型的算术表达式中, 最宽的数据类型成为目标转换类型。 intival=3; doubledval=3.14159; ival+dval;//ival...
  • 持续学习总结输出中,今天分享的是Web前端,JS基础之类型转换、隐式转换显式转换JavaScript是弱数据类型: JavaScript也不知道变量到底属于那种数据类型,只有赋值了才清楚。使用表单、prompt 获取过来的数据默认是...
  • string strType = "123";...//可以不要,隐式转换, 要的为显式转换  string strType2 = (string)objType; //必须要,显式转换  int intType = (int)strType; //错误,不能通过编译  int intType = (int)o...
  • 隐式转换和显式转换

    2018-03-30 11:04:45
    自定义类型:有两种函数可以进行隐式转换,单参数构造函数 隐式类型转换符。自定义类型可以用函数前+ explicit 关键字,防止转换。单个参数的构造函数,或可传单个参数的类构造函数Example 1:class things{ ...
  • 显式转换和隐式转换

    2021-06-19 10:52:48
    显式转换:从表示范围大的类型转换为表示范围小的类型,需要强制转换。 强制类型转换的语法格式就是加一个括号,然后给出想要转换的类型。 例如: double x = 9.876; int y = (int)x; 这个时候 y 的结果为 9。因为...
  • 1、js数据类型 ...Undefined、Null的特殊情况以及Boolean的转换都比较好记忆。剩下的只需要关注好 String、Number 这两种类型。 1种对象类型: Object 2、类型转换 数据类型间的转换可分为: 原始值间的转换
  • 显式转换是指使用某种语法告诉程序进行转换的地方.例如(在Java中):int i = 999999999;byte b = (byte) i; // The type cast causes an explicit conversionb = i; // Compilation error!! No implicit conversion ...
  • 隐式强制转换是一种将值转换为另一种类型的方法,这个过程是自动完成的,无需我们手动操作。 假设我们下面有一个例子。 console.log(1+'6');//16 console.log(false+true);//1 console.log(6*'2');//12 第一个...
  • C++的隐式显式转换

    2022-01-25 22:15:22
    隐式转换不仅存在于基本类型,还存在于成员属性隐式转为对象,而explicit可以禁止隐式转换
  •  string strType = "123...//可以不要,隐式转换, 要的为显式转换 string strType2 = (string)objType; //必须要,显式转换 int intType = (int)strType; //错误,不能通过编译 int intType = (int)objType; /
  • 今天在做051的96题时遇见了NVL2(exp 1,exp 2,exp 3)这个函数,他需要三个参数,其中exp 1 可以是任何数据类型,而exp 2exp 3 数据类型有时会出现不一致,这是oracle就会进行隐式转换。隐式数据类型转换将按照下面...
  • C语言【隐式类型转换显式类型转换】的详解

    千次阅读 多人点赞 2022-05-18 15:10:25
    本期介绍 ...而类型转换的方式一般可分为隐式类型转换(也称:自动类型转换显示类型转换(也称:强制类型转换),两者有着本质上的区别。隐式类型转换是由编译器自动进行的,不需要人为的干预,而且
  • 当我们需要隐式转换的时候,我们就需要用implicit关键字。 隐式转换的时候,他会先全局的查找是否有匹配的方法或者参数,如果没有再考虑隐式转换。 由于隐式参数是根据类型的,所以同一作用域不能定义多个同一个类型...
  • 参考:C++类型转换:隐式转换和显式转换 隐式转换 当一个值拷贝给另一个兼容类型的值时,隐式转换会自动进行。所谓隐式转换,是指不需要用户干预,编译器私下进行的类型转换行为。 隐式转换类型 基本数据类型:...
  • 隐式转换(Implicit Conversions) 如果将一个运算符应用于多个不同类型,编译器会试图隐式地把其中一个操作数的类型转换为另一个操作数的类型。赋值操作在同样的情况下也会这样。 一般来说,如果转换后不会造成信息...
  • C# 隐式转换和显式转换

    千次阅读 2018-01-17 01:55:10
    3、由于 Rect 类 不能隐式转换为 double ,所以使用关键字 implicit 对 Rect 类 自定义 隐式转换 4、返回的类型必须目标类型一致 或 可以转换为目标类型的类型 5、Rect 类 不能显示转换为 int ,使用关键字 ...
  • 自定义隐式转换和显式转换c#简单例子 (出自朱朱家园http://blog.csdn.net/zhgl7688) 例子:对用户user中,用户名first name和last name进行转换成合成一个限定长度为10个字符新name。 自定义隐式转换: ...
  • 在java中我们经常会遇到...隐式转换:从表示范围小的类型转换为表示范围大的类型,可以直接转换,称为隐式转换。 隐式类型转换又可以成为自动类型转换,就是由系统自动完成的类型转换。 例:short x = 5; int y =...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 89,565
精华内容 35,826
关键字:

隐式转换和显式转换