explicit
Constructors and Conversion OperatorsRecall that we’ve been declaring as explicit
every constructor that can be called with one argument, including multiparameter constructors for which we specify default arguments. With the exception of copy constructors, any constructor that can be called with a single argument and is not declared explicit
can be used by the compiler to perform an implicit conversion. The constructor’s argument is converted to an object of the class in which the constructor is defined. The conversion is automatic—a cast is not required.
In some situations, implicit conversions are undesirable or error-prone. For example, our Array
class in Fig. 10.10 defines a constructor that takes a single int
argument. The intent of this constructor is to create an Array
object containing the number of elements specified by the int
argument. However, if this constructor were not declared explicit
it could be misused by the compiler to perform an implicit conversion.
Unfortunately, the compiler might use implicit conversions in cases that you do not expect, resulting in ambiguous expressions that generate compilation errors or result in execution-time logic errors.
The program (Fig. 10.12) uses the Array
class of Figs. 10.10–10.11 to demonstrate an improper implicit conversion. To allow this implicit conversion, we removed the explicit keyword from line 13 in Array.h
(Fig. 10.10).
Line 10 in main
(Fig. 10.12) instantiates Array
object integers1
and calls the single-argument constructor with the int
value 7
to specify the number of elements in the Array
. Recall from Fig. 10.11 that the Array
constructor that receives an int
argument initializes all the Array
elements to 0. Line 11 in Fig. 10.12 calls function outputArray
(defined in lines 16–19), which receives as its argument a const
Array&
to an Array
. The function outputs the number of elements in its Array
argument and the contents of the Array
. In this case, the size of the Array
is 7
, so seven 0
s are output.
Line 12 calls function outputArray
with the int
value 3
as an argument. However, this program does not contain a function called outputArray
that takes an int
argument. So, the compiler determines whether the argument 3
can be converted to an Array
object. Because class Array
provides a constructor with one int
argument and that constructor is not declared explicit
, the compiler assumes the constructor is a conversion constructor and uses it to convert the argument 3
into a temporary Array
object containing three elements. Then, the compiler passes the temporary Array
object to function outputArray
to output the Array
’s contents. Thus, even though we do not explicitly provide an outputArray
function that receives an int
argument, the compiler is able to compile line 12. The output shows the contents of the three-element Array
containing 0
s.
The reason we’ve been declaring every single-argument contructor preceded by the keyword explicit
is to suppress implicit conversions via conversion constructors when such conversions should not be allowed. A constructor that’s declared explicit
cannot be used in an implicit conversion. In the example of Figure 10.13, we use the original version of Array.h
from Fig. 10.10, which included the keyword explicit
in the declaration of the single-argument constructor in line 13
explicit Array(int = 10); // default constructor
Figure 10.13 presents a slightly modified version of the program in Fig. 10.12. When this program in Fig. 10.13 is compiled, the compiler produces an error message, such as
'void outputArray(const Array &)': cannot convert argument 1
from 'int' to 'const Array &'
on Visual C++, indicating that the integer value passed to outputArray
in line 12 cannot be converted to a const
Array&
. Line 13 demonstrates how the explicit
constructor can be used to create a temporary Array
of 3
elements and pass it to function outputArray
.
Always use the explicit
keyword on single-argument constructors unless they’re intended to be used as conversion constructors.
explicit
Conversion OperatorsJust as you can declare single-argument constructors explicit
, you can declare conversion operators explicit
to prevent the compiler from using them to perform implicit conversions. For example, the prototype
explicit MyClass::operator string() const;
declares MyClass
’s string
cast operator explicit
, thus requiring you to invoke it explicitly with static_cast
.