C++ explicit

发布时间 2023-09-18 15:53:38作者: ydqun

C++ explicit

explicit关键字有两个用途:

  1. 指定构造函数或者转换函数(C++11起)为显示,即它不用用于隐式转换和赋值初始化。
  2. 可以与常量表达式一同使用。当该表达式为true才为显示转换(C++20起)。

1.将构造函数标记为显式

C++中的explicit关键字通常用来将构造函数标记为显式类型转换,即在创建对象的时候不能进行隐式转换。
可以通过一个例子理解:

/*************************************************************************
        > File Name: 01.cpp
        > Author:
        > Mail:
        > Created Time: Mon 18 Sep 2023 02:12:16 PM CST
 ************************************************************************/
#include <iostream>
using namespace std;

class Complex {
private:
    double real;
    double imag;

public:
    Complex(double r = 0.0, double i = 0.0)
        : real(r)
        , imag(i)
    {
    }

    bool operator==(Complex rhs)
    {
        return (real == rhs.real && imag == rhs.imag)
                    ? true
                    : false;
    }
};

int main()
{
    Complex com1(3.0, 0.0);

    if (com1 == 3.0)
        cout << "Same" << endl;
    else
        cout << "Not Same" << endl;

    return 0;
}

编译并执行:

ydqun@ydqhost explicit % g++ 01-without-explicit.cpp                                                                                                                                                             [0]
ydqun@ydqhost explicit % ./a.out                                                                                                                                                                                 [0]
Same

在上述例子中,main函数里构建了com1实例,并且用com1和double类型的3.0进行比较,此时double类型的3.0被隐式转换成Complex类型。
我们可以避免这种隐式转换,因为它们可能会导致意外的结果。我们可以通过explicit关键字使构造函数变成显式。例如,如果我们尝试使用以下带有explicit关键字的构造函数,就会出现编译错误。

#include <iostream>
using namespace std;

class Complex {
private:
    double real;
    double imag;

public:
    explicit Complex(double r = 0.0, double i = 0.0)
        : real(r)
        , imag(i)
    {
    }

    bool operator==(Complex rhs)
    {
        return (real == rhs.real && imag == rhs.imag)
                    ? true
                    : false;
    }
};

int main()
{
    Complex com1(3.0, 0.0);

    if (com1 == 3.0)
        cout << "Same" << endl;
    else
        cout << "Not Same" << endl;

    return 0;
}

给构造函数添加了explicit关键字修饰后,此时编译会出现如下错误:

ydqun@ydqhost explicit % g++ 01-without-explicit.cpp                                                                                                                                                             [0]
01-without-explicit.cpp: In function ‘int main()’:
01-without-explicit.cpp:34:14: error: no match for ‘operator==’ (operand types are ‘Complex’ and ‘double’)
   34 |     if (com1 == 3.0)
      |         ~~~~ ^~ ~~~
      |         |       |
      |         Complex double
01-without-explicit.cpp:22:10: note: candidate: ‘bool Complex::operator==(Complex)’
   22 |     bool operator==(Complex rhs)
      |          ^~~~~~~~
01-without-explicit.cpp:22:29: note:   no known conversion for argument 1 from ‘double’ to ‘Complex’
   22 |     bool operator==(Complex rhs)

这时候需要我们进行显式转换。

#include <iostream>
using namespace std;

class Complex {
private:
    double real;
    double imag;

public:
    explicit Complex(double r = 0.0, double i = 0.0)
        : real(r)
        , imag(i)
    {
    }

    bool operator==(Complex rhs)
    {
        return (real == rhs.real && imag == rhs.imag)
                    ? true
                    : false;
    }
};

int main()
{
    Complex com1(3.0, 0.0);

    if (com1 == (Complex)3.0)  //此处对double类型的3.0进行显式转换为Complex
        cout << "Same" << endl;
    else
        cout << "Not Same" << endl;

    return 0;
}

编译并输出:

ydqun@ydqhost explicit % g++ 02-with-explicit.cpp                                                                                                                                                                [0]
ydqun@ydqhost explicit % ./a.out                                                                                                                                                                                 [0]
Same

2.与常量表达式一同使用

explicit关键字可以与常量表达式一起使用。但是,如果常量表达式的计算结果为true,此时构造函数是显式的;否则,构造函数是
隐式的。

#include <iostream>

constexpr bool ENABLE_EXPLICIT = false;

class Foo {
public:
    explicit(ENABLE_EXPLICIT)
    Foo(int i) : m_i(i) {}
private:
    int m_i;
};

int main()
{
    Foo a = 1;
}

编译可以通过,但是如果把变量ENABLE_EXPLICIT改为true,则会出现如下编译错误:

ydqun@ydqhost explicit % g++ 03-explicit.cpp -std=c++2a                                                                                                                                                          [0]
03-explicit.cpp: In function ‘int main()’:
03-explicit.cpp:21:13: error: conversion from ‘int’ to non-scalar type ‘Foo’ requested
   21 |     Foo a = 1;

注意,编译以上例程需要在C++20及以上才能编译通过。