• C++——隐式类型转换


    隐式类型转换(构造函数的隐式调用)

    先看一下隐式类型转换如何发生吧:

    #include 
    using namespace std;
    
    class point {
        public:
        	int x,y;
        	point(int x=0, int y=0):x(x),y(y) {}
    }
    
    void displayPoint(const point &p)
    {
    	cout << "( " << p.x << "," << p.y << " )";
    }
    
    int main()
    {
       displayPoint(1);
        point p = 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    我们定义了一个很简单的point类,它的构造函数使用了默认参数(int x=0, int y=0),这时main函数里的两句都触发了构造函数的隐式调用

    如果构造函数不使用默认参数,会在编译时报错

    很显然,函数displayPoint需要的是point类型的参数,而我们传入一个int数据,这个程序能够成功运行,并且成功输出(1,0)说明隐式调用了构造函数。另外需要注意的是,在对象刚刚定义的时候,使用赋值操作符=,调用的是构造函数,而不是operator=运算符

    这种悄然发生的事情,有时可以带来便利,让你的程序可以继续运行,而更多的会带来很多意想不到的结果,explict关键字用来避免这样的情况发生

    explicit 关键字

    c++11中对explicit的解释为指定构造函数或转换函数(operator type())为显示,即它不能用于隐式转换和复制初始化

    在上面point示例中,构造函数被explicit修饰后,就不能被隐式调用了,主函数中的两句声明定义将不会通过编译

    能用就用

    如果我们能预料某种情况的发生,就不要把这个情况控制权交给编译器。即使没有加explicit的构造函数,我们也应该先声明point p(1),再把p作为参数传递给displayPoint函数

    Effective C++中也写到

    被声明为explicit的构造函数通常比non-explicit兄弟更受欢迎,因为它们禁止编译器执行非预期(往往也不被期望)的类型转换,除非我有一个好理由允许构造函数被用于隐式类型转换,否则我会把它声明为explicit,我鼓励你遵循同样的政策

    operator用于隐式类型转换

    C++中的operator主要有两种作用,一是操作符重载,二是自定义对象类型的隐式转换。在上面提到的point类中,我们提到如果构造函数没有默认参数,隐式转换的时候就会编译出错,但是如果我们利用operator的第二个作用,就可以自定义隐式转换类型。

    #include 
    #include 
    using namespace std;
    
    class point {
        public:
            point(int x, int y):x(x),y(y) {
                cout << "constructor" << endl;
            }
    
            bool operator()(int x, int y) {
                cout << "opearator overload" << endl;
                return x>this->x && y>this->y;
            }
    
            operator string() {
                cout << "type convert" << endl;
                string str = "(" + x;
                str += "," + y;
                str += ")";
                return str;
            }
        private:
            int x,y;
    };
    
    int main()
    {
        // part1
       point p1(5,6);
       if(p1(10,9)){
           cout << "point(10,9) is larger than  point(5,6)" << endl;
       }
       
        // part2
       string str(p1);
    	cout << str;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    运行结果如下:

    主函数的part1调用的是operator的重载作用,我们主要探讨part2的隐式转换作用。我们往string类的构造函数中传递的point类,显然string类中必然没有以point类为参数的构造函数,但是从运行结果来看,这次构造是成功的。

    如果string类有默认参数的构造函数,那么string str(p1)会隐式调用该默认参数的构造函数来构造string。对于没有默认参数的构造函数情况下,类的隐式类型转换,是使用一个其他类型构造当前类的临时对象,并用此临时对象来构造当前对象,这种转换必须有其他类型的构造函数支持;而operator算子的隐式类型转换,就是使用当前类型对象生成另一个类型的对象(正好与没有默认参数构造函数情况下,类的隐式转换相反),这种转换必须有operator算子的支持。

    在这个例子中,string str(p1)是将point类对象转换成string类对象,使用的是string类的隐式构造(转换),string类不存在有默认参数的构造函数,也不存在以point类为参数的构造函数,那么string类就需要去point类中去找以operator算子修饰的将point类转为string类的转换函数,并调用该函数,最终返回的string临时对象,被string类用来拷贝构造成一个新的string对象str

    参考文章
    C++ explicit 关键字

  • 相关阅读:
    Java Queue队列
    iOS 面试题以及自我理解答案
    4.网络游戏逆向分析与漏洞攻防-游戏启动流程漏洞-模拟游戏登陆器启动游戏并且完成注入
    Flutter介绍
    优先队列(priority_queue)用法详解
    Hadoop-19 Flume Agent批量采集数据到HDFS集群 监听Hive的日志 操作则把记录写入到HDFS 方便后续分析
    RPC 核心原理理论分析
    motionface respeak新的aigc视频与音频对口型数字人
    越复杂的CoT越有效吗?Complexity-Based Prompting for Multi-step Reasoning
    NK-RTU980 Camera 关键参数
  • 原文地址:https://blog.csdn.net/m0_56722204/article/details/128159935