C++显式构造函数 [翻译]

来源:互联网 发布:淘宝新手开店培训 编辑:程序博客网 时间:2024/06/01 21:43

原文地址:http://www.codeproject.com/KB/cpp/explicit_constructor_CPP.aspx
简介

构造函数的确能使你的类变的简单优雅,它也是一个基本的函数,可以由编译器以默认的方式提供给你,即默认构造函数。在c++中,如果你只写一行代码。
Class A{};
编译器会提供给你一个默认的、无参数的构造函数,并伴随一个析构函数,一个拷贝构造函数(copy Constructor),一个拷贝复制操作符(copy assignment operator)

背景

那么什么是显式构造函数?
为了方便理解显式构造函数,我们首先需要理解隐式转换,让我们看一下它在代码中的作用,以及什么时候不需要这些特性。
使用以下代码,例1:思考下面这个传统而简单的复数类:

  1. #include <iostream>
  2. using std::cout;
  3. using std::endl;
  4. class complexNumbers {
  5.   double real, img;
  6. public:
  7.   complexNumbers() : real(0), img(0) { }
  8.   complexNumbers(const complexNumbers& c) { real = c.real; img = c.img; }
  9.   complexNumbers( double r, double i = 0.0) { real = r; img = i; }
  10.   friend void display(complexNumbers cx);
  11. };
  12. void display(complexNumbers cx){
  13.   cout<<"Real Part: "<<cx.real<<" Imag Part: "<<cx.img<<endl;
  14. }
  15. int main() {
  16.   complexNumbers one(1);
  17.   complexNumbers five = 5;
  18.   display(one);
  19.   display(five);
  20.   return 0;
  21. }

 

这个复数类很简单,它包括实数复数两部分,代码定义了一个默认的构造函数,一个拷贝构造函数,以及着重定义了另一个构造函数,用它来帮我们做一些隐式的构造。
在main函数中,我们首先创建了一个名为one 和一个名为 five的对象,由于隐式转换的作用,它们都能成功调用。故对象one的实数为1,虚数为 0;对象five的实数为5,虚数0.我们可以使用复数类中的 “display”方法打印出来,对隐式转换的理解,这是一个很好的例子。输出结果如下:

Real Part: 1 Imag Part: 0
Real Part: 5 Imag Part: 0

 

下面我们考虑这个例子:

  1. #include <iostream>
  2. using std::cout;
  3. using std::endl;
  4. class complexNumbers {
  5.   double real, img;
  6. public:
  7.   complexNumbers() : real(0), img(0) { }
  8.   complexNumbers(const complexNumbers& c) { real = c.real; img = c.img; }
  9.   complexNumbers( double r, double i = 0.0) { real = r; img = i; }
  10.   friend void display(complexNumbers cx);
  11. };
  12. void display(complexNumbers cx){
  13.   cout<<"Real Part: "<<cx.real<<" Imag Part: "<<cx.img<<endl;
  14. }
  15. int main() {
  16.   complexNumbers one(1);
  17.   display(one);
  18.   display(300);
  19.   return 0;
  20. }

 

类似的例子,只是在main方法中多加了一行,display(300),继续,输出结果变为:

Real Part: 1 Imag Part: 0
Real Part: 300 Imag Part: 0
 

“邦”!!!这不是我们希望的结果,首先代码本身就不清楚,display(300)什么意思?display 方法的参数期待的是复数类的一个对象/实例,而300根本不是,那么这种情况是如何发生的呢?
因为display方法期待一个复数类的一个对象/实例,当我们把300这个十进制数传进去是,在将300这个十进制数传到复数类的一个临时对象时,发生了一次隐式转换。(因此,300就赋值给临时对象的实数了)。
那么怎么解决这种情况呢??
很简单,强制编译器只能通过显示构造来创建对象,技巧如下:

  1. #include <iostream>
  2. using std::cout;
  3. using std::endl;
  4. class complexNumbers {
  5.   double real, img;
  6. public:
  7.   complexNumbers() : real(0), img(0) { }
  8.   complexNumbers(const complexNumbers& c) { real = c.real; img = c.img; }
  9.   explicit complexNumbers( double r, double i = 0.0) { real = r; img = i; }
  10.   friend void display(complexNumbers cx);
  11. };
  12. void display(complexNumbers cx){
  13.   cout<<"Real Part: "<<cx.real<<" Imag Part: "<<cx.img<<endl;
  14. }
  15. int main() {
  16.   complexNumbers one(1);
  17.   display(one);
  18.   complexNumbers two =2;
  19.   display(200);
  20.   return 0;
  21. }

 

思考下面的语句:

  1. explicit complexNumbers( double r, double i = 0.0) { real = r; img = i; }

此时我们强制编译器在这段代码中不能使用隐式转换,如果程序员写包含隐式转换的代码,编译器将返回一个错误。

  1. bash-3.2$ g++ -g -o hello test2.cpp 
  2. test2.cpp: In function ‘int main()’:
  3. test2.cpp:22: error: conversion from ‘int’ to non-scalar type ‘complexNumbers’ requested
  4. test2.cpp:23: error: conversion from ‘int’ to non-scalar type ‘complexNumbers’ requested

 

鉴于此,程序员应当用下面的方法实现:
display(complexNumbers(200)); //只允许显示转换…………