explicit constructor

This post will introduce a key word explicit that can forbid the implicit type casting by constructor with only one parameter.

Implicit type casting

In C++ class, a constructor with only one parameter (or parameters with default values except the first one) has two functions. One is to contruct an object, another is that will be called when an implicit type casting is performed. However, this is not always good. In some cases, it will lead to logical error.

implicit_casting
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
#include <iostream>
using namespace std;
class MyString {
public:
MyString(const char* p) {
cout << "char constructor" << endl;
}
MyString(int n) {
cout << "int constructor" << endl;
}
};
int main() {
MyString s1("Hello"); // explicit call MyString(const char* p)
MyString s2(1); // explicit call MyString(int n)
MyString s3 = "Hello"; // implicit call MyString(const char* p)
MyString s4 = 1; // implicit call MyString(int n)
char chr = 'a';
MyString s5 = chr; // implicit call MyString(int n) with type casting
return 0;
}

The result is:

result
1
2
3
4
5
char constructor
int constructor
char constructor
int constructor
int constructor // s5, implict casting

In this case, chr is a char type and MyString s5 = chr; will be interpreted by compiler as MyString s5 = MyString((int)chr) where chr is implicitly cast to int. This logical error is caused by the constructor MyString(int n) which make this implicit casting enable. To avoid this, the key word explicit should be used to restrict it.

implicit_casting
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
#include <iostream>
using namespace std;
class MyString {
public:
MyString(const char* p) {
cout << "char constructor" << endl;
}
explicit MyString(int n) {
cout << "int constructor" << endl;
}
};
int main() {
MyString s1("Hello"); // explicit call MyString(const char* p)
MyString s2(1); // explicit call MyString(int n)
MyString s3 = "Hello"; // implicit call MyString(const char* p)
MyString s4 = 1; // error, invalid conversion from ‘int’ to ‘const char*’
char chr = 'a';
MyString s5 = chr; // error, invalid conversion from ‘char’ to ‘const char*’
return 0;
}

To restrict by explicit, only MyString(const char* p) can be used for implicit casting and it will cause compile-time error.

Copy contructor

There are three cases where the implicit casting will be performed by copy constructor.

  1. An object is passed into a function by pass-by-value.
  2. An object is retured from a function by pass-by-value.
  3. Call like: Myclass myobj1 = myobj2; where myobj2 is another object of Myclass.

So if restricting a copy constructor by explicit, all operations above will cause error in compiling. That means explicit is not a good design for copy constructor.