zoukankan      html  css  js  c++  java
  • 31 转换构造函数,类型转换函数

    1 再论类型转换

    • 标准数据类型之间会进行隐式的类型安全转换

    • 转换规则

      char  -> 
        ↓      int -> unsigned int -> long -> unsigned long -> float -> double
      short -> 
      
    • 示例1:基本数据类型之间的隐式类型转换

      • Demo

        #include <iostream>
        #include <string>
        
        using namespace std;
        
        int main()
        {   
            short s = 'a';           // 隐式类型转换:char->short
            unsigned int ui = 1000;  // 隐式类型转换:int->unsigned int
            int i = -2000;
            double d = i;            // 隐式类型转换:int->double
            
            cout << "d = " << d << endl;            // -2000
            cout << "ui = " << ui << endl;          // 1000
            cout << "ui + i = " << ui + i << endl;  // 4294966296 = unsigned int + (unsigned int)(int) => 1000 + (unsgined int)(-2000) => 1000 +  
            
            // unsigned int + int => unsigned int + (unsigned int)int => unsigned int > 0
            if( (ui + i) > 0 ) {
                cout << "Positive" << endl;
            }
            else {
                cout << "Negative" << endl;
            }
            
            // short + char => (int)short + (int)char => int
            cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl;  // 4
            
            return 0;
        }
        
      • 编译运行

        -2000
        1000
        
        Positive
        4
        
    • 【问题】普通类型与类类型之间能否进行类型转换?类类型之间能否进行类型转换?

      • 普通类型 => 类类型:转换构造函数
      • 类类型 => 普通类型:类型转换函数
      • 类类型 => 类类型:类型转换函数/转换构造函数

    2 普通类型 ---> 类类型?

    • 示例2:普通类型 => 类类型

      • Demo1:直接尝试 int => Test

        #include <iostream>
        
        using namespace std;
        
        class Test
        {
        };
        
        int main()
        {   
            Test t;
            
            t = 5;  // int => Test
            
            return 0;
        }
        
      • 编译

        test.cpp: In function ‘int main()’:
        test.cpp:13:7: error: no match for ‘operator=’ (operand types are ‘Test’ and ‘int’)
             t = 5;
               ^
        test.cpp:5:7: note: candidate: Test& Test::operator=(const Test&)
         class Test
               ^
        test.cpp:5:7: note:   no known conversion for argument 1 from ‘int’ to ‘const Test&’
        
      • Demo2:利用强制类型转换

        #include <iostream>
        
        using namespace std;
        
        class Test
        {
        };
        
        int main()
        {   
            Test t;
            
            t = (Test)5;  // int => Test
            
            return 0;
        }
        
      • 编译

        test.cpp: In function ‘int main()’:
        test.cpp:14:15: error: no matching function for call to ‘Test::Test(int)’
             t = (Test)5;
                       ^
        test.cpp:5:7: note: candidate: Test::Test()
         class Test
               ^
        test.cpp:5:7: note:   candidate expects 0 arguments, 1 provided
        test.cpp:5:7: note: candidate: Test::Test(const Test&)
        test.cpp:5:7: note:   no known conversion for argument 1 from ‘int’ to ‘const Test&’
        
      • Demo3:利用构造函数 => 编译通过

        #include <iostream>
        
        using namespace std;
        
        class Test
        {
        public:
            Test() {
                
            }
            // 带一个参数的构造函数
            Test(int i) {
                
            }
        };
        
        int main()
        {   
            Test t;
            
            t = Test(5);  // 利用生成的临时对象赋值
            
            return 0;
        }
        
      • Demo4:再次尝试 int ---> Test => 编译成功 => 为什么这里成功?

        #include <ios tream>
        
        using namespace std;
        
        class Test
        {
        public:
            Test() {
                
            }
            Test(int i) {
                
            }
        };
        
        int main()
        {   
            Test t;
            
            t = 5;  // int -> Test 成功
            
            return 0;
        }
        
    • 【分析】再论构造函数

      • 构造函数可以定义不同类型参数

      • 参数满足下列条件时成为转换构造函数

        • 有且仅有一个参数
        • 参数是基本类型或其它类类型(只要不是自己当前的类型即可)
      • 另一个视角

        • 旧式的 C 方式强制类型转换
        int i;
        Test t;
        
        i = int(1.5);  // C 方式的强制类型转换
        t = Test(100);  // C 方式的强制类型转换:本质是调用类的构造函数
        
      • 编译器会尽力尝试让源码通过编译

        Test t;
        t = 100;
        
        • 100 这个立即数默认为 int 类型,常规上是不能赋值给 Test 类的 t 对象的,但当遇到转换构造函数时会发生变化!
        • 如果 Test 这个类中定义了转换构造函数 Test(int i); ,就可以进行隐式类型转换(普通类型 ---> 类类型),默认等价于:t = Test(100);
    • 编译器尽力尝试的结果是隐式类型转换

      • 隐式类型转换会让程序以意想不到的方式进行工作
      • 隐式类型转换是工程中 bug 的重要来源
    • 示例3:隐式类型转换的危害

      • Demo

        #include <iostream>
        #include <string>
        
        using namespace std;
        
        class Test
        {
            int mValue;
        public:
            Test() {
                mValue = 0;
            }
            
            // 转换构造函数
            Test(int i) {
                mValue = i;
            }
            
            // +操作符重载函数
            Test operator + (const Test& p) {
                Test ret(mValue + p.mValue);
                
                return ret;
            }
            
            int value() {
                return mValue;
            }
        };
        
        int main()
        {   
            Test t;
            
            t = 5;  // <=> t = Test(5);
            
            Test r;
            
            r = t + 10;  // 这里编译通过:Test + int  => r = t + Test(10);
            
            cout << r.value() << endl;  // 15
            
            return 0;
        }
        
      • 编译运行

        15
        
      • 分析:代码行 r = t + 10; 编译通过,其原因是转换构造函数(Test(int i);)的存在,从而进行了隐式类型转换,等价于:r = t + 10; => r = t + Test(10); 。而这段代码很可能是手误,极有可能造成 bug

    • 工程中通过 explicit 关键字杜绝编译器的转换尝试

      • 转换构造函数被 explicit 修饰时只能进行显式转换

      • 转换方式

        • static_cast<ClassName>(value); : C++
        • ClassName(value); : C
        • (ClassName)value; : C,不推荐
      • 示例4:转换方式

        • Demo1

          #include <iostream>
          #include <string>
          
          using namespace std;
          
          class Test
          {
              int mValue;
          public:
              Test()
              {
                  mValue = 0;
              }
              
              explicit Test(int i)
              {
                  mValue = i;
              }
              
              Test operator + (const Test& p)
              {
                  Test ret(mValue + p.mValue);
                  
                  return ret;
              }
              
              int value()
              {
                  return mValue;
              }
          };
          
          int main()
          {   
              Test t;
                 
              t = 5;
              
              Test r;
              
              r = t + 10;
              
              cout << r.value() << endl;
              
              return 0;
          }
          
        • 编译

          test.cpp: In function ‘int main()’:
          test.cpp:37:7: error: no match for ‘operator=’ (operand types are ‘Test’ and ‘int’)
               t = 5;
                 ^
          test.cpp:6:7: note: candidate: Test& Test::operator=(const Test&)
           class Test
                 ^
          test.cpp:6:7: note:   no known conversion for argument 1 from ‘int’ to ‘const Test&’
          test.cpp:41:11: error: no match for ‘operator+’ (operand types are ‘Test’ and ‘int’)
               r = t + 10;
                     ^
          test.cpp:20:10: note: candidate: Test Test::operator+(const Test&)
               Test operator + (const Test& p)
          
        • Demo2

          #include <iostream>
          #include <string>
          
          using namespace std;
          
          class Test
          {
              int mValue;
          public:
              Test()
              {
                  mValue = 0;
              }
              
              explicit Test(int i)
              {
                  mValue = i;
              }
              
              Test operator + (const Test& p)
              {
                  Test ret(mValue + p.mValue);
                  
                  return ret;
              }
              
              int value()
              {
                  return mValue;
              }
          };
          
          int main()
          {   
              Test t;
              
              t = static_cast<Test>(5);    // t = Test(5);
          
              Test r;
              
              r = t + static_cast<Test>(10);   // r = t + Test(10);
              
              cout << r.value() << endl;  //15
              
              return 0;
          }
          

    4 类类型 ---> 普通类型?

    • 【问题】类类型是否能够类型转换到普通类型?

    • 可以,利用类型转换函数

    • 类型转换函数

      • C++ 类中可以定义类型转换函数

      • 类型转换函数用于将类对象转换为其他类型

      • 语法规则

        operator Type()
        {
            Type ret;
            //...
            return ret;
        }
        
    • 示例5:类型转换函数

      • Demo

        #include <iostream>
        #include <string>
        
        using namespace std;
        
        class Test
        {
            int mValue;
        public:
            Test(int i = 0) {
                mValue = i;
            }
            int value() {
                return mValue;
            }
            // 类型转换函数
            operator int () {
                return mValue;
            }
        };
        
        int main()
        {   
            Test t(100);
            int i = t;  // <=> int i = t.operator int ();
            
            cout << "t.value() = " << t.value() << endl;  // 100
            cout << "i = " << i << endl;  // 100
            
            return 0;
        }
        
    • 类型转换函数

      • 转换构造函数具有同等的地位
      • 使得编译器有能力将对象转换为其他类型
      • 编译器能够隐式的使用类型转换函数
    • 编译器会尽力尝试让源码通过编译

      Test t(1);
      int i = t;
      
      • t 对象为 Test 类型,为什么可以用于初始化 int 类型的变量:因为 Test 类中定义了类型转换函数 operator int(); ,可以进行转换 (相当于这个对象隐式地调用类型转换函数)

    5 类类型之间的转换

    • 【问题】类类型之间可以相互转换么?

    • 可以,类型转换函数和转换构造函数

    • 示例6:

      • Demo1:利用类型转换函数

        #include <iostream>
        #include <string>
        
        using namespace std;
        
        class Value
        {
        public:
            Value() {
            }
        };
        
        class Test
        {
            int mValue;
        public:
            Test(int i = 0) {
                mValue = i;
            }
            int value() {
                return mValue;
            }
            // 类型转换函数
            operator Value() {
                Value ret;
                cout << "operator Value()" << endl;
                return ret;
            }
        };
        
        int main()
        {   
            Test t(100);
            Value v = t;  // <=> Value v = t.operator Value ();
            
            return 0;
        }
        
      • 编译运行

        operator Value()
        
      • Demo2:利用转换构造函数

        #include <iostream>
        #include <string>
        
        using namespace std;
        
        class Value
        {
        public:
            Value() {
            }
            // 转换构造函数
            Value(Test& t) {
                cout << "Value(Test& t)" << endl;
            }
        };
        
        class Test
        {
            int mValue;
        public:
            Test(int i = 0) {
                mValue = i;
            }
            int value() {
                return mValue;
            }
        };
        
        int main()
        {   
            Test t(100);
            Value v = t;  // <=> Value v = Value(t)
            
            return 0;
        }
        
      • 编译运行

        Value(Test& t)
        
    • 类型转换函数 VS 转换构造函数

      • 类型转换函数和转换构造函数同时存在时,编译器会混淆选择

      • Demo

        #include <iostream>
        #include <string>
        
        using namespace std;
        
        class Test;
        
        class Value
        {
        public:
            Value() {
            }
            // 转换构造函数
            Value(Test& t) {
            }
        };
        
        class Test
        {
            int mValue;
        public:
            Test(int i = 0) {
                mValue = i;
            }
            int value() {
                return mValue;
            }
            // 类型转换函数
            operator Value()
            {
                Value ret;
                cout << "operator Value()" << endl;
                return ret;
            }
        };
        
        int main()
        {   
            Test t(100);
            Value v = t;
            
            return 0;
        }
        
      • 编译

        test.cpp: In function ‘int main()’:
        test.cpp:40:35: error: conversion from ‘Test’ to ‘Value’ is ambiguous
             Value v = static_cast<Test&>(t);
                                           ^
        test.cpp:27:9: note: candidate: Test::operator Value()
                 operator Value(){
                 ^
        test.cpp:14:9: note: candidate: Value::Value(Test&)
                 Value(Test& t){
                 ^
        
      • 改进:给 Test 类添加 exlpicit 关键字

        #include <iostream>
        #include <string>
        
        using namespace std;
        
        class Test;
        
        class Value
        {
        public:
            Value() {
            }
            // 转换构造函数加以限制
            explicit Value(Test& t) {
            }
        };
        
        class Test
        {
            int mValue;
        public:
            Test(int i = 0) {
                mValue = i;
            }
            int value() {
                return mValue;
            }
            // 类型转换函数
            operator Value() {
                Value ret;
                cout << "operator Value()" << endl;
                return ret;
            }
        };
        
        int main()
        {   
            Test t(100);
            Value v = t
            
            return 0;
        }
        
      • 编译运行

        operator Value()
        
    • 无法抑制隐式的类型转换函数调用

    • 类型转换函数可能与转换构造函数冲突

    • 工程中以 Type toType() 的公有成员代替类型转换函数

    • 示例:Qt 文件

      • Demo

        #include <QDebug>
        #include <QString>
        
        int main()
        {
            QString str = "";
            int i = 0;
            double d = 0;
            short s = 0;
        
            str = "-255";
            //使用Type toType()公有成员函数
            i = str.toInt();
            d = str.toDouble();
            s = str.toShort();
        
            qDebug() << "i = " << i << endl;  //-255
            qDebug() << "d = " << d << endl;  //-255
            qDebug() << "s = " << s << endl;  //-255
        
            return 0;
        }
        
  • 相关阅读:
    年度总结会议
    2018年度移动创新竞赛组总结
    移动竞赛组2019计划
    task ':app:mergeDebugResources' property 'aapt2FromMaven'
    SQL SERVER : 'GO' 附近有语法错误问题
    Visual C# 访问 SQLserver 数据库
    数据库系统概论 第三章 课后作业
    数据库系统概论 第三章 建表&插入SQL语句
    【pyqt5 QtDesigner SQLserver2017】 Python3.6 Demo
    【Win10 + PyCharm + Python + PyQt5 + pymssql】 Python 3.6 访问 SQLserver 2017(对话框界面)1
  • 原文地址:https://www.cnblogs.com/bky-hbq/p/13903888.html
Copyright © 2011-2022 走看看