zoukankan      html  css  js  c++  java
  • Conversion function 转换函数

    Conversion function个人理解为是一个跟重载配合使用的重要结构,我们经常会对一些对象进行类型转换,比如把一个Double类型转为Int类型,或是float类型转Double类型,那么当我们构建自己的类的时候,我们希望当它与某种类型进行相加相减之类的操作时,能够自动将自己转换为对应的类型,亦是将另外一种类型转换成跟自己相同的类型,然后进行你设定好的操作。

    一般来说,设定这种转化函数,必须是符合逻辑的,不能随意改变,否则会对程序整体造成不好的影响。

    就拿分数类来进行解释。

    class Fraction {
    public:
        Fraction(int num,int den = 1):m_numerator(num),m_denominator(den){}
        operator double() const {
            return (double)m_numerator / m_denominator;
        }
    
    private:
        int m_numerator; // 分子
        int m_denominator; //分母
    };

    比如上面的代码,我们分数类有两个属性,一个分子,一个分母,且都是int类型,那么假如,我们想把这个分数类的对象与某个整数,或者是浮点数相加,那么该怎么做呢,比如下面这个操作:

    int main()
    {
    Fraction f(3, 5);
    double d = 4 + f;
    ...
    }

    很明显,我们想要得到的结果是 3/5 + 4的结果,可是 4 是一个整形,而f是你自己构建的类的对象,两种完全不相同的东西,如何相加呢。

    可以再回到我们最上面那一段代码:

     operator double() const {
            return (double)m_numerator / m_denominator;
        }

    可能之前对重载有些许过了解的人,会对这段代码产生疑惑,一般是重载一个运算符,那么operator double() 是什么意思呢,其实很简单,意思就是,当对象与其他类型的变量进行运算时,编译器会先找你的类里面,有没有相关的设定,可以让你的对象变为一个类型并且能够符合当前的状况,比如运行到 double d = 4 + f;这里,编译器就开始找你的Fraction类里有什么可以使用的类型,operator double()就是表示,我这个类的对象,可以作为一个double类型使用,并且作为double类型使用时,应该变成一个什么样的double值,很明显,一个分数如何变成double值,当然是分子除以分母。

    好了,那么新的问题又来了,万一它其中有多个重载类型呢,那将会发生什么。

    class Fraction {
    public:
        Fraction(int num,int den = 1):m_numerator(num),m_denominator(den){}
        operator double() const {
            return (double)m_numerator / m_denominator;
        }
        operator int() const {
            return (int)m_numerator / m_denominator;
        }
    private:
        int m_numerator; // 分子
        int m_denominator; //分母
    };

    看到这段代码,我们发现,又多了一个operator int(),最开始说了,C++能处理的,都会自己处理,因为遇到的都是它觉得是这样,或者只能是这样的状况,那么当前这种情况下, 它再次遇到 double d = 4 + f;时,它找你的类中相应的转换函数,发现既可转换成 double,也可以转换成int,而且这两个都能与4相加,C++并不知道你到底想要f以什么样的类型面对这个4,所以就会报错。

    遇到这种状况很简单,要么你告诉编译器你想做什么,要么就把可能性排掉只剩下一种(逻辑正确性就体现在这,如果逻辑思路正确,一般是不会分出很多种情况)。

    我们当然可以告诉编译器我们想做什么,只需要:

    int main()
    {
    Fraction f(3, 5);
    double d = 4 + (int)f;
    ...
    }

    或者

    int main()
    {
    Fraction f(3, 5);
    double d = 4 + (double)f;
    ...
    }

    这样编译器就知道你想要f以什么样的姿势面对这个整形变量了。

    我们也能得到想要的值。

    那么Fraction类对象能转化为其他的类型,那么是否能将这个"4"转换为Fraction类型呢,答案是可以的.

    non-explicit-one-argument ctor

    看下面这一段代码:

    class Fraction {
    public:
        Fraction(int num,int den = 1):m_numerator(num),m_denominator(den){}
    
        Fraction operator+ (const Fraction& f) {
            return Fraction(...);
        }
    private:
        int m_numerator; // 分子
        int m_denominator; //分母
    };

    此时再遇到 

    Fraction f(3,5);
    Fraction d2 = f + 4;

    会如何,我们想得到一个Fraction类的对象,并且得到相应的值,是f + 4,此时应该怎么做,很明显,我们应该把4变成Fraction类,理所当然4就是 4/1,所以在 operator+ 中,我们直接调用构造函数,创建并返回一个分子为4,分母为1的Fraction类对象,因为Fraction(int num,int den = 1)可以看出,构造函数分母初始化为1,传值为4会赋值给num,所以得到4/1,具体相加的操作可以继续在重载函数中实现,这里就不具体操作了。

    刚刚可以看到上面有个non-explicit-one-argument ctor ,这是什么意思呢,其实就是构造函数是非explicit类型,explicit是用来干什么的,之前说了,编译器觉得你想要干什么,会帮你去做,不加explicit就是让编译器能干就干,如果加上explicit就是让编译器不要去揣测,放这别去碰这个构造函数。

    由于我们之前没有加explicit,所以当你把4变成一个Fraction类对象时,编译器看到分母den = 1 有初始值,所以会把4当做没有初始值的num,并调用构造函数。

    而如果我们加上explicit,编译器就不会做这个动作,并且也我们也就无法实现上面那个操作了。

    这里可以用两个例子来说明:

    class Fraction {
    public:
        Fraction(int num,int den = 1):m_numerator(num),m_denominator(den){}
        operator double() const {
            return (double)m_numerator / m_denominator;
        }
        Fraction operator+ (const Fraction& f) {
            return Fraction(...);
        }
    private:
        int m_numerator; // 分子
        int m_denominator; //分母
    };

    比如说这串代码,当它遇到 

    Fraction f(3,5);
    Fraction d2 = f + 4;

    它也是无法执行的,因为编译器不知道你是要将4转为Fraction类,还是要将f转为double型,编译器就会报错:

    Error:ambiguous

    而如果你加上 explicit ,也就是

    class Fraction {
    public:
        explicit Fraction(int num,int den = 1):m_numerator(num),m_denominator(den){}
        operator double() const {
            return (double)m_numerator / m_denominator;
        }
        Fraction operator+ (const Fraction& f) {
            return Fraction(...);
        }
    private:
        int m_numerator; // 分子
        int m_denominator; //分母
    };

    此时,编译器就不会把 4 变为 4/1 了,因为编译器不会去揣测你的意思了,它不会去调用这个构造函数去把4变成4/1,然后由于我们要得到的d2 是 Fraction类型的,f变为double类型与4相加,会出现什么情况,

    想象一样 Fraction d2 = 4.6 ;  这样能行吗,肯定不行,所以我们会看到这种报错:

    Error:conversion from "double" to "Fraction" requested

    以上就是对Conversion function转换函数的一点粗略理解。

  • 相关阅读:
    用leangoo看板工具实施多团队大规模敏捷开发
    单团队的Scrum敏捷开发-leangoo
    放弃在每日站会上按成员逐个发言
    Leangoo思维导图做OKR目标管理
    好用的思维导图软件(程序员必备)
    好用免费的思维导图工具,多人协作共同编辑
    什么是Scrum燃尽图?
    Scrum中文网-团队需要Scrum Master做这六件事
    项目管理工具Leangoo自定义字段的应用
    实施敏捷开发中,选择看板管理工具的几个要点
  • 原文地址:https://www.cnblogs.com/xiangqi/p/14287333.html
Copyright © 2011-2022 走看看