详解 c++ 关键字 explicit

    用了很久的C++ 了,今天突然被小伙伴问道,构造函数前的explicit 关键字什么作用,于是自己也只能支支吾吾的说出“为了显式调用……”很尴尬啊……典型的知道所以然不知道其所以然……好吧,搜搜资料好好地充充电……

    首先说定义,C++ 中的explicit关键字只能用于修饰只有一个参数的类构造函数,它的作用是表明该构造函数是显式的,而非隐式的。跟他对应的另一个关键字是implicit,意思是隐藏的,类构造函数默认情况下就是声明为implicit(隐式的)。

这里的重点就是 只能 修饰 只有一个参数的 类的构造函数。也就是说,

一、只可以修饰类的构造函数,一般的函数不能修饰。

二、只有类的构造函数有一个参数时候,才有效,当有多个参数时候就没什么意义了(这里有个例外,就是当除了第一个参数以外的其他参数都有默认值的时候,explicit依然有效,此时调用构造函数时只传入一个参数,等效于只有一个参数的类构造函数)。

我们先来看看什么是显式调用,什么是隐式调用:

class MyClass   //没有使用explicit关键词,默认为隐式声明
{
public:
    int m_size;
    char *m_pStr;

    MyClass(int size)                        //没有使用explicit关键词,默认为隐式声明
    {
        m_size = size;                        //大小
        m_pStr = (char *)malloc(size + 1);    //给m_pstr 分配size的大小的内存
        memset(m_pStr, 0, size + 1);
    }

    MyClass(const char *pStr)                //没有使用explicit关键词,默认为隐式声明
    {
        m_size = strlen(pStr);
        m_pStr = (char *)malloc(m_size + 1);  //给m_pstr分配内存
        strcpy(m_pStr, pStr);                //复制内容
    }

    MyClass(int size, const char *pStr)    //参数为两个,所以不管是否使用explicit关键字,都是无效的。
    {
        m_size = size;
        int size1 = strlen(pStr);    //大小
        m_pStr = (char *)malloc(size1 + 1);  //给m_pstr分配内存
        strcpy(m_pStr, pStr);
    }

};
 
 

下面是调用:


    MyClass c1(10);         // ok, 显式调用 MyClass(int size)
    MyClass c2 = 12;        // ok, 隐式调用 MyClass(int size)
    MyClass c3;             // 错误, 没有响应的构造函数
    MyClass c4("hello");    // ok, 显式调用 MyClass(const char *pStr)
    MyClass c5 = "nihao";   // ok, 隐式调用
    MyClass c6(5, "hello"); // ok, 显式调用 MyClass(int size, const char *pStr)

    c1 = 5;                 // ok, 隐式调用 MyClass(int size)
    c2 = 6;                 // ok, 隐式调用 MyClass(int size)
    c4 = "hello world";     // ok, 隐式调用 MyClass(const char *pStr)

    c3 = c1;                // 错误, 编译是没问题的,但是必须在类里重载“=”运算符才行

    上面代码 c2 = 12; c5 = "nihao"为什么是可以的呢?

    因为在C++中,如果构造函只有一个参数时,那么编译的时候就会有一个缺省的转换操作:将该构造函数对应的数据类型的数据转换为该类对象。

    也就是说MyClass c2 = 12;等同于MyClass c2(12);

    但是上面的代码中的MyClass c2(12),中12表示分配内存大小,那么c2 = 12 与5 = "nihao"这样的隐式转换显得不伦不类,容易被误解,怎么避免使用这样的隐式转换呢?答案就是使用关键字explicit,我们将类中的构造函数添加上explicit关键字试试:

class MyClass
{
public:
    int m_size;
    char *m_pStr;

    explicit MyClass(int size)
    {
        m_size = size;                //大小
        m_pStr = (char *)malloc(size + 1);    //给m_pstr 分配size的大小的内存
        memset(m_pStr, 0, size + 1);
    }

    explicit MyClass(const char *pStr)
    {
        m_size = strlen(pStr);
        m_pStr = (char *)malloc(m_size + 1);  //给m_pstr分配内存
        strcpy(m_pStr, pStr);         //复制内容
    }

    explicit MyClass(int size, const char *pStr)        //两个参数,所以添加explicit是无效的。
    {
        m_size = size;
        int size1 = strlen(pStr);    //大小
        m_pStr = (char *)malloc(size1 + 1);  //给m_pstr分配内存
        strcpy(m_pStr, pStr);
    }

};

再次编译一下结果如下:


    

    发现隐式调用的全部错误,这就是使用关键字explicit,显式调用的效果。也就是说,关键字explicit的作用就是防止够咱函数的隐式转换。

    上面也说过了,explicit关键字只对有一个参数的类构造函数有效,如果函数的参数大于或者等于两个时候,是不会产生隐式转换的,所以explicit也就是无效的。一个例外就是,当除了第一个参数意外其他参数都有默认值的时候,explicit关键字依然有效,此时当调用构造函数时,只传入一个参数,等同于只有一个参数的类构造函数。

  explicit MyClass(int size, const char *pStr = "hello")
    {
        m_size = size;
        int size1 = strlen(pStr);    //大小
        m_pStr = (char *)malloc(size1 + 1);  //给m_pstr分配内存
        strcpy(m_pStr, pStr);
    }

上面这种情况,explicit也是有效的!

猜你喜欢

转载自blog.csdn.net/xiezhongyuan07/article/details/80257420