跳转至

自动类型转换

1、使用构造函数进行自动类型转换

两个类,calss One和class Two, class Two的构造函数参数传一个One。那么就可以把类One转为类Two。

如果不想构造函数进行自动类型转换可以在前面加explicit,这种构造函数只能进行创建对象,不能自动类型转换。

class One {
public:
    One(){}
};

class Two {
public:
//    explicit Two(const One&) {}
    Two(const One&) {}
};

void f(Two) {}

void test() {
    One one;
//    f(Two(one));
    f(one);
}

2、使用运算符进行自动类型转换,类似运算符重载

把Four变成Three,参数传four会自动的转变为three。

class Three {
    int i;
public:
    Three(int ii = 0, int = 0) : i(ii) {}
};

class Four {
    int x;
public:
    Four(int xx) : x(xx) {}
    operator Three() const { return Three(x); }
};

void g(Three) {}

调用:

four变成three是用的上面的利用运算符转换

1变成three是用的Three的构造函数

void test() {
    Four four(1);
    g(four);//four -> three
    g(1);//1 -> three
}

都发生了自动类型转换。

例:整型转为Number类型

//整型转为Number类型
class Number {
    int i;
public:
    Number(int ii = 0) : i(ii) {}
    //定义加法运算符重载
    const Number operator+(const Number& n) const {
        return Number(i + n.i);
    }
    //减法做成友元
    friend const Number operator-(const Number&, const Number&);
};

const Number operator-(const Number& n1, const Number& n2) {
    return Number(n1.i - n2.i);
}

调用测试:

void test() {
    Number a(47), b(11);
    a + b;
    a + 1; //1 -> Number
    //1 + a;
    a - b;
    a - 1; //1 -> Number
    1 - a; //1 -> Number
}

1+a不可以。加法是一个成员函数,只有一个参数。

1-a可以,减法是友元,全局函数,两个参数。1会变成Number。

自动类型优缺点

优点

自定义的字符串类,字符串类有很多方法,长度,字符串比较等等。要把所有的字符串操作函数都做出来就太多了。

如果使用自动类型转换就不用写那么多方法了。

使用自动类型转换,变成C语言的字符串。

class MyString {
    string s;
public:
    MyString(const string& str = "") : s(str) {}

    //    int strcmp(const MyString& S) const {
    //        return ::strcmp(s.c_str(), S.s.c_str());
    //    }

    operator const char*() const {
        return s.c_str();
    }
};

然后就可以直接使用标准库里的函数去比较。

void test() {
    MyString s1("Hello"), s2("there");
    //    s1.strcmp(s2);
    ::strcmp(s1, s2);
    ::strspn(s1, s2);
}

库函数都可以使用。不用在新定义的类里面重写一遍。重写一遍很繁琐。

缺点

把苹果变成橘子

  1. 利用运算符把苹果变成橘子
  2. 利用构造函数把苹果变成橘子
class Orange {
public:
        //    Orange(Appple);
};

class Pear {};

class Apple {
public:
    operator Orange() const { return Orange(); }
    operator Pear() const { return Pear(); }
    //    Orange toOrange();
    //    Orange makeOrange();
    //    Pear toPear();
    //    Pear makePear();
};

void k(Orange) {}

void eat(Orange);
void eat(Pear);

void test() {
    Apple apple;
    k(apple);
    //    eat(apple);
}

两种方法都有的时候,C++不知道使用哪个方法把苹果变成橘子

解决方法就是不要写两种方法,只用一种就可以了。

苹果可以变成橘子,苹果可以变成梨。吃苹果的时候,C++不知道变哪个。不做成自动类型转换。用成员函数明确的显示的转换。而不是自动类型转换。

class Apple {
public:
    //    operator Orange() const { return Orange(); }
    //    operator Pear() const { return Pear(); }
    Orange toOrange();
    Orange makeOrange();
    Pear toPear();
    Pear makePear();
};

fo转换成Fee

class Fi{};

class Fee {
public:
    Fee(int) {}
    Fee(const Fi&) {}
};

class Fo {
    int i;
public:
    Fo(int x = 0) : i(x) {}
    operator Fee() const { return  Fee(i); }
};

void test() {
    Fo fo;
    Fee fee = fo;//fo -> fee
}

fo转换成Fee。Fee有C++默认赋值运算符重载。非常灵活。

只做必要的类型转换,不要做过多的类型转换,容易出错。合理使用。