An explicit constructor can prevent unwanted
implicit casting when creating an object.
For example,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
class Bar {
public:
/*explicit*/ Bar(int a) { }
};
void foo(Bar b)
{
}
int main()
{
foo(3); // error if constructor is explicit
foo(Bar(3)); // works either way
}
| |
The above code will compile just fine.
But, if you uncomment the explicit to the constructor, it will give you a compiler error.
So when to use it?
Allowing implicit casting can lead to behavior that the programmer might not expect to happen. Passing a 3 into a function that expects something other an an int can be confusing.
Here's another example:
Let's say you have a custom String class, and one of the constructors for this class take in an int, which signifies the amount of characters to reserve (allocate) for the string.
And then you have a print function that takes in a String.
Now, the user of your code wants to use your print function. They write
writeLine(42);
but nothing is printed!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
// Example program
#include <iostream>
#include <string>
class String {
public:
String(const char* c_str)
: str(c_str)
{
}
String(int n)
{
str.reserve(n);
}
private:
std::string str;
friend std::ostream& operator<<(std::ostream&, const String&);
};
// Operator overload to allow printing with cout << operator
std::ostream& operator<<(std::ostream& os, const String& str)
{
return os << str.str;
}
void writeLine(String str)
{
std::cout << str << "\n";
}
int main()
{
writeLine(3);
}
| |
But... let's add an explicit to the constructor.
1 2 3 4
|
explicit String(int n)
{
str.reserve(n);
}
| |
Now, we get a compiler error. This error is good in that it prevents the user of your class/function from causing unexpected or ambiguous behavior.
1 2 3 4
|
In function 'int main()':
36:16: error: invalid conversion from 'int' to 'const char*' [-fpermissive]
7:5: note: initializing argument 1 of 'String::String(const char*)'
| |
Maybe the user of the code should write
writeLine("3");
instead.
This is a bit of a contrived example, but I hope it makes sense.