Use the keyword explicit in C ++

Reading to see the explicit keywords to make a note of it, put it in more clear, relatively shallow.

 

In C ++, we can sometimes be used as a constructor of automatic type conversion function. However, this automatic feature is not always desirable, and sometimes lead to unexpected type conversion, therefore, C ++ new keyword explicit, for closing this automatic feature. I.e. modified keyword explicit class constructor can not be automatically implicit type conversion, only explicit type conversions.

Note: Only a constructor parameter with a constructor or n parameters, but the n-1 parameters provide a default value, such a case can be cast.

The following shows the specific application (without explicit case) by a code:

 

 1 /* 示例代码1 */
 2 class Demo
 3 {
 4    public:
 5     Demo();                     /* 构造函数1 */
 6     Demo(double a);              /* 示例代码2 */
 7     Demo(int a,double b);           /* 示例代码3 */
 8     Demo(int a,int b=10,double c=1.6);  /* 示例代码4 */
 9     ~Demo();
10     void Func(void);
11 
12     private:
13     int value1;
14     int value2;
15 };

 

Above four constructors:

1 no argument constructor can not be cast!

2 has a constructor parameter type conversion may be performed, such as: Demo test; test = 12.2; such a call is equivalent to 12.2 Demo implicitly convertible to type.

3 constructor has two parameters, and no default value, it can not use the type conversion!

4 constructor has three parameters, two parameters have default values, it may be implicit conversions, such as: Demo test; test = 10;.

 

The following describes the case of using the keyword explicit:

 

 1  1 /* 示例代码2 */
 2  2 class Demo
 3  3 {
 4  4    public:
 5  5     Demo();                     /* 构造函数1 */
 6  6     explicit Demo(double a);        /* 示例代码2 */
 7  7     Demo(int a,double b);           /* 示例代码3 */
 8  8  
 9  9     ~Demo();
10 10     void Func(void);
11 11 
12 12     private:
13 13     int value1;
14 14     int value2;
15 15 };

 

In the above second constructor, since the keyword explicit, implicit conversion is not possible. Namely: Demo test; test = 12.2; is invalid! But we can show the type of conversion, such as:

Demo test;

test = Demo (12.2); or

test = (Demo)12.2;

 

 

 

What is implicit conversion?

It is well known basic types of C ++ is not entirely in opposition, between portions of the data may be made implicit type conversion.

The so-called implicit conversion, is that does not require user intervention, compiler type conversion behavior in private. Many times users may not know what made the conversion.

 Why implicit conversion?

C ++ object-oriented multi-state properties, is achieved by the type of package to subclasses of the parent class.

By implicit conversion, you can directly use the object a subclass return type of the superclass.

For example, the numerical and Boolean type conversion, integer and floating point conversion like.

In some ways, the implicit conversion to C ++ application developers to bring no small convenience.

C ++ is a strongly typed language, the type of inspection is very strict.

If there is no type of implicit conversion, which will give application developers to bring a lot of inconvenience.

Of course, everything has two sides, one side when you enjoy convenient, you have to face too smart or even completely out of your control.

Risk appeared unwittingly.

 Principle implicit conversion of C ++

  • Basic data types in a data type to a basic range as the basis for the conversion (to ensure the accuracy is not lost).
    Implicit conversion takes place in small -> large conversion. For example, conversion from char to int.
    From int- "long.
  •  Custom object subclass object implicitly convert the parent class object.

C ++ implicit conversion occurs conditions

  • Mixed types of arithmetic expressions. E.g:

    1

    2

    3

    int a = 3;

    double b = 4.5;

    a + b; // a将会被自动转换为double类型,转换的结果和b进行加法操作

  •  Different types of assignment. E.g:

    1

    2

    int a = true; (bool类型被转换为int类型)

    int * ptr = null;(null被转换为int*类型)

  •  Function parameters by value. E.g:

    1

    2

    void func(double a);

    func(1); // 1被隐式的转换为double类型1.0

  •  Function return values. E.g:

    1

    2

    3

    4

    double add(int a, int b)

    {

        return a + b;

    //运算的结果会被隐式的转换为double类型返回

      Reference #: http://developer.51cto.com/art/201002/183139.htm

      # Implicit conversion in the above four cases, satisfy a basic principle: low accuracy - "high-precision conversion.

      Does not satisfy this principle, implicit conversion is not happening.

      Of course, this time we can use explicit type conversions with respect to the (known as cast), using the following method:
       Double A = 2.0;
       int = B (int) A;

     Use Casts can lead to loss of precision, so be sure to make sure you've got enough grasp during use.

Risk implicit conversions

Risk implicit conversion is typically present in from class constructor defined.

By default regulations, only a constructor parameter also defines an implicit conversion, corresponding to the data type constructors data into the class object.

  •  Example One
    as shown below:

    1

    2

    3

    4

    5

    6

    7

    8

    class String

    {

    public:

        String ( const char* p ); // 用C风格的字符串p作为初始化值

        //…

    }

     

    String s1 = “hello”; //OK 隐式转换,等价于String s1 = String(”hello”)

    But sometimes you may not need this implicit conversion, as follows:

    1

    2

    3

    4

    5

    6

    7

    8

    class String

    {

    public:

        String ( int n ); //本意是预先分配n个字节给字符串

        String ( const char* p ); // 用C风格的字符串p作为初始化值

     

        //…

    }

    Comparison of two normal wording:
    String S2 (10); // allocate 10 bytes of the OK empty string
    String s3 = String (10); // OK 10 bytes allocated empty string

    of two written on comparison doubts:
    string S4 = 10; // compiler, 10 bytes are allocated empty string
    string s5 = 'a'; // compiler, dispensing int ( 'a') byte empty string
    s4 and s5 respectively, and char to an int type, implicitly converted into a number of bytes allocated empty string, misleading.
    Reference #: http://blog.csdn.net/smilelance/article/details/1528737
  •  Example two
    following cases:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    class Test

    {

    public:

      Test(int a);

      bool isSame(Test other)

      {

        return m_val == other.m_val;

      }

     

    private

      int m_val;

    }

    Called as follows:
    Test A (10);
    the If (a.isSame (10)) // returns true statement that

    originally used to compare two Test objects, and even equal to the int type.
    This is due to the implicit conversion happens, the actual comparison is a temporary Test object.
    This program is absolutely impermissible.

Prohibit implicit conversion

Since there is so much implicit conversion risk, how can that happen prohibit implicit conversion of it.

C ++ provides explicit keyword, when coupled with explicit constructor declaration of keywords can prohibit implicit conversion. Use as follows:

1

2

3

4

5

6

class Test

{

explicit Test(int a);

……

 

}

 

Plus the keywords later, as the operation is legal:

1

Test(10);

Following the operation becomes illegal:

1

Test aa = 10; 

This can effectively prevent the implicit conversion, thereby enabling precise control of the program, to improve the quality of the object.

 

"C ++ Primer" is mentioned:

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

这里应该注意的是, “可以用单个形参进行调用” 并不是指构造函数只能有一个形参,而是它可以有多个形参,但那些形参都是有默认实参的。

那么,什么是“隐式转换”呢? 上面这句话也说了,是从 构造函数形参类型 到 该类类型 的一个编译器的自动转换。

下面通过代码来看一看:

 

#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std ;
class BOOK  //定义了一个书类
{
    private:
        string _bookISBN ;  //书的ISBN号
        float _price ;    //书的价格

    public:
        //定义了一个成员函数,这个函数即是那个“期待一个实参为类类型的函数”
        //这个函数用于比较两本书的ISBN号是否相同
        bool isSameISBN(const BOOK & other ){
            return other._bookISBN==_bookISBN;
                }

        //类的构造函数,即那个“能够用一个参数进行调用的构造函数”(虽然它有两个形参,但其中一个有默认实参,只用一个参数也能进行调用)
        BOOK(string ISBN,float price=0.0f):_bookISBN(ISBN),_price(price){}
};

int main()
{
    BOOK A("A-A-A");
    BOOK B("B-B-B");

    cout<<A.isSameISBN(B)<<endl;   //正经地进行比较,无需发生转换

    cout<<A.isSameISBN(string("A-A-A"))<<endl; //此处即发生一个隐式转换:string类型-->BOOK类型,借助BOOK的构造函数进行转换,以满足isSameISBN函数的参数期待。
    cout<<A.isSameISBN(BOOK("A-A-A"))<<endl;    //显式创建临时对象,也即是编译器干的事情。
    
    system("pause");
}

 

     代码中可以看到,isSameISBN函数是期待一个BOOK类类型形参的,但我们却传递了一个string类型的给它,这不是它想要的啊!还好,BOOK类中有个构造函数,它使用一个string类型实参进行调用,编译器调用了这个构造函数,隐式地将stirng类型转换为BOOK类型(构造了一个BOOK临时对象),再传递给isSameISBN函数。

  隐式类类型转换还是会带来风险的,正如上面标记,隐式转换得到类的临时变量,完成操作后就消失了,我们构造了一个完成测试后被丢弃的对象。

  我们可以通过explicit声明来抑制这种转换:

explicit BOOK(string ISBN,float price=0.0f):_bookISBN(ISBN),_price(price){}

    explicit关键字只能用于类内部的构造函数声明上.这样一来,BOOK类构造函数就不能用于隐式地创造对象了,编译上面的代码会出现这样的提示:

  现在用户只能进行显示类型转换,显式地创建临时对象。

 

  总结一下:

  1.   可以使用一个实参进行调用,不是指构造函数只能有一个形参。
  2.   隐式类类型转换容易引起错误,除非你有明确理由使用隐式类类型转换,否则,将可以用一个实参进行调用的构造函数都声明为explicit。
  3.       explicit只能用于类内部构造函数的声明。它虽然能避免隐式类型转换带来的问题,但需要用户能够显式创建临时对象(对用户提出了要求)。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/qq_35886593/article/details/90691040