Use of explicit keyword in C++

Use of explicit keyword in C++, you should know

This blog post explains the importance and use of the “explicit keyword in C++”. You will learn here when and how to use the explicit keyword in C++ programming with some example codes. But before going in depth-first we need to know that an explicit keyword is a function specifier,  like virtual.

Note: Function-specifiers can be used only in function declarations.

What is the explicit keyword in C++?

Prefixing the explicit keyword to the constructor prevents the compiler from using that constructor for implicit conversions. So it is a good practice to add explicit keyword with constructors.

According to the standard “The explicit specifier shall be used only in the declaration of a constructor or conversion function within its class definition”. Let’ see an example where I am using the explicit specifier with a constructor,

class A
{
public:
    explicit A(int i);
    // ...
};

When need to use the explicit keyword?

A constructor declared without the function-specifier “explicit” specifies a conversion from the types of its parameters (if any) to the type of its class. Such a constructor is called a converting constructor.

Note:  Until C++11, a single parameter constructor is called a converting constructor.

struct A
{
    A() { }         // converting constructor (since C++11)  
	
    A(int) { }      // converting constructor
	
    A(int, int) { } // converting constructor (since C++11)
};

 

Let see a code to understand the use of the explicit keyword,

#include<iostream>
using namespace std;

class Demo
{
private:
    int data;
    
public:
    Demo(int i):data(i)
    {
    }
    
    void Display()
    {
        cout<<" data = "<<data<<endl;
    }
};


int main()
{
    Demo obj(6);
    obj.Display();

    obj = 27; // implicit conversion occurs here.

    obj.Display();

    return 0;
}

 

In the above-mentioned code, you can see how the constructor is working as a conversion constructor when assigning 27 to the object. When you will compile this code then it would be compiled and display the value of data.

 

I think you want to avoid this accidental construction because it can hide a bug. So using the explicit keyword we can avoid it. Because we know that prefixing the explicit keyword to the constructor prevents the compiler from using that constructor for implicit conversions. Let see a code to understand this concept.

#include<iostream>
using namespace std;

class Demo
{
private:
    int data;
    
public:
    explicit Demo(int i):data(i)
    {
    }
    void Display()
    {
        cout<<" data = "<<data<<endl;
    }
};
int main()
{
    Demo obj(6);
    obj.Display();
    
    //error: copy-initialization does not consider Demo::Demo(int)
    obj = 27;
    
    obj.Display();
    
    return 0;
}

Output:

explicit keyword c++

If you want to learn a programming language online, you can check the courses, a free trial is available.

Let’s see another example code that explains the difference between non-explicit and explicit constructors.

Example 1:

In the below example, I am using a non-explicit constructor for the struct X. You can see that these constructors work like converting constructors, also they support copy-initialization.

#include
using namespace std;

struct X
{
    X(int) {}
    X(const char*, int =0) {}
    X(int, int) {}
};


void f(X arg)
{
    // OK: copy-initialization selects X::X(int)
    X a = 1; // a = X(1)

    // OK: copy-initialization selects X::X(const char*, int =0)
    X b = "Amlendra"; // b = X("Amlendra",0)

    // OK: copy-list-initialization selects X::X(int, int)
    X c = {4, 5}; // c = X(4,5)


    // OK: direct-initialization selects X::X(int)
    X d(2);


    // OK: direct-list-initialization selects X::X(int, int)
    X e{4, 5};

    // OK: direct-list-initialization selects X::X(int, int)
    X f("Amlendra");

    // OK: explicit cast performs static_cast, direct-initialization
    X g = (X)1;

    a = 2; // a = X(2)
}

int main()
{
    f(3); // f(X(3))

    f({1, 2}); // f(X(1,2))

    return 0;
}

Note: Code will be compile on C++11 or later compiler. If still, you have doubt, write a comment in the comment box.

Example 2:

In the below example, I am using the explicit function specifier with the constructors of struct X. The explicit constructors support only direct initialization (which also includes explicit conversions such as static_cast),

#include
using namespace std;

struct X
{
    explicit X();
    explicit X(int);
    explicit X(int, int);
};



int main()
{
    X a; // OK: default-initialization performed

    X b{}; // OK: direct initialization syntax used

    X c = {}; // error: copy-list-initialization

    X d = 1; // error: no implicit conversion

    X e = X(1); // OK: direct initialization syntax used

    X f(1); // OK: direct initialization syntax used

    X* g = new X(1); // OK: direct initialization syntax used

    X h = (X)1; // OK: explicit cast used

    X i = static_cast(1); // OK: explicit cast used

    X j = { 3, 4 }; // error: no implicit conversion

    return 0;
}

Summary:

If you will add explicit function specifiers, then only explicit conversions (direct initialization or explicit cast operation) occurs. But with non-explicit constructors and conversion function implicit and explicit both conversions occurs. See the below table,

 

    Types                        explicit conversion          implicit conversion

 explicit constructor                    yes                          no

 constructor                             yes                          yes

 explicit conversion function            yes                          no

 conversion function                     yes                          yes