C++隐式类类型转换


C++可以定义如何将其他类型的对象隐式转换为我们的类类型或将我们的类类型的对象隐式转换为其他类型。为了定义到类类型的隐式转换,需要定义合适的构造函数。

说明:可以用单个实参来调用的构造函数定义了从形参类型到该类类型的一个隐式转换。

class Sales_item
{
public:
    Sales_item(const string &book = "") : isbn(book), units_sold(0), revenue(0.0) {}
    Sales_item(istream &is);
};

这两个构造函数都定义了一个隐式转换。因此,在期待一个Sales_item类型对象的地方可以使用一个string或一个istream对象。

string null_book = "9-999-99999-9";
item.Same_isbn(null_book);

这段代码使用一个string类型对象作为实参传递给Sales_item的Same_isbn成员函数,该成员函数期待一个Sales_item对象作为实参。编译器将使用接受一个string的构造函数从null_book生成一个新的Sales_item对象。新生成的(临时的)Sales_item对象被传递给Same_isbn。

item.Same_isbn(cin);

这段代码将cin对象隐式转换为Sales_item对象,这个转换执行接受一个istream的构造函数。这两个Sales_item是临时对象,一旦Same_isbn结束,就不能再访问它。

下面看一个例子:

 1 #include <string>
 2 #include <iostream>
 3 using namespace std;
 4
 5 class Fruit                                //定义一个类,名字叫Fruit
 6 {
 7    string name;                        //定义一个name成员         
 8    string colour;                        //定义一个colour成员
 9
10 public:
11    bool isSame(const Fruit &otherFruit)  //期待的形参是另一个Fruit类对象,测试是否同名
12    {
13        return name == otherFruit.name;
14    }
15    void print()              //定义一个输出名字的成员print()
16    {
17        cout<<colour<<" "<<name<<endl;
18    }
19    Fruit(const string &nst,const string &cst = "green"):name(nst),colour(cst){}  //构造函数
20
21    Fruit(){}
22 };
23
24 int main(void)
25 {
26    Fruit apple("apple");
27    Fruit orange("orange");
28    cout<<"apple = orange ?: "<<apple.isSame(orange)<<endl;  //没有问题,肯定不同
29    cout<<"apple = apple ?:"<<apple.isSame(string("apple"))<<endl; //用一个string做形参?
30
31    return 0;
32 }

我们用string("apple")类型作为一个期待Fruit类型形参的函数的参数,结果是正确的。当把构造函数colour的默认实参去掉,也就是定义一个对象必须要两个参数的时候,文件编译不能通过。Fruit apple("apple")其实也已经有了一个转换,从const char *的C字符串格式,转为string。但apple.isSame("apple")这样调用肯定是错的,必须要用string()来先强制转换,然后系统才知道帮你从string隐式转换为Fruit。当然你也可以显式帮它完成,apple.isSame(Fruit("apple"))。

可以通过将构造函数声明为explicit,来防止在需要隐式转换的上下文中使用构造函数。explicit关键字只能用于类内部的构造函数声明上。在类的定义体外部所做的定义不再重复它。虽然不能隐式转换了,但显式转换还是可以的,例如:apple.isSame(Fruit("apple"))。

说明:

(1)显式使用构造函数只是终止了隐式地使用构造函数。任何构造函数都可以用来显式地创建临时对象。

(2)通常,除非有明显的理由想要定义隐式转换,否则,单形参构造函数应该为explicit。将构造函数设置为explicit可以避免错误,并且当转换有用时,用户可以显式地构造对象。

(3)将构造函数设置为explicit的好处是可以避免因隐式类型转换而带来的语义错误,缺点是当用户的确需要进行相应的类型转换时,不能依靠隐式类型转换,必须显式地创建临时对象。

------------------------------分割线------------------------------

C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码

读C++ Primer 之构造函数陷阱

读C++ Primer 之智能指针

读C++ Primer 之句柄类

将C语言梳理一下,分布在以下10个章节中:

  1. Linux-C成长之路(一):Linux下C编程概要
  2. Linux-C成长之路(二):基本数据类型
  3. Linux-C成长之路(三):基本IO函数操作
  4. Linux-C成长之路(四):运算符
  5. Linux-C成长之路(五):控制流
  6. Linux-C成长之路(六):函数要义
  7. Linux-C成长之路(七):数组与指针
  8. Linux-C成长之路(八):存储类,动态内存
  9. Linux-C成长之路(九):复合数据类型
  10. Linux-C成长之路(十):其他高级议题

本文永久更新链接地址:

相关内容