A conversion constructor takes an argument of another type and builds an object of its class type. A one-parameter constructor can therefore let the compiler convert values silently, often when a function call or operator needs a different type. section 2.2 section 9.8
The hidden conversion cost
In a Complex class with Complex(double real, double imag = 0), expressions such as c1 + 3.14159 and 2.71828 + c1 silently construct temporary Complex objects. The four-line example performs six constructor calls; more complex types could also incur destructor calls. The code is correct, but the hidden work can make performance and maintenance harder to assess. section 9.8
Use explicit when callers should not receive uncontrolled implicit conversions: explicit Complex(double real, double imag = 0) still permits direct construction but prevents the compiler from using the constructor for automatic conversions. When mixed-type operations are intentional, provide overloaded operators for the supported types instead of relying on conversion. section 2.2 section 9.8
Listing 9.20 Implicit, silent, and expensive constructor type conversions
class Complex {
private:
double real;
double imag;
public:
Complex(double real, double imag=0) : real(real), imag(imag) {}
double getReal() const { return real; }
double getImag() const { return imag; }
};
const Complex operator+(const Complex& lhs, const Complex& rhs) {
return Complex(lhs.getReal()+rhs.getReal(), lhs.getImag()+rhs.getImag());
}
int main() {
Complex c1(2.2); #1
Complex c2 = c1 + 3.14159; #2
Complex c3 = 2.71828 + c1; #3
Complex c4 = 2.71828 + 3.14159; #4
}
Inspect the Complex example to trace where implicit conversions create temporary objects. section 9.8
Listing 9.21 Minimizing constructor conversions by providing overloaded operators
class Complex {
private:
double real;
double imag;
public:
Complex(double real, double imag=0) : real(real), imag(imag) {}
double getReal() const { return real; }
double getImag() const { return imag; }
};
const Complex operator+(const Complex& lhs, const Complex& rhs) {
return Complex(lhs.getReal()+rhs.getReal(), lhs.getImag()+rhs.getImag());
}
const Complex operator+(const Complex& lhs, double rhs) { #1
return Complex(lhs.getReal()+rhs, lhs.getImag());
}
const Complex operator+(double lhs, const Complex& rhs) { #2
return Complex(lhs+rhs.getReal(), rhs.getImag());
}
int main() {
Complex c1(2.2);
Complex c2 = c1 + 3.14159;
Complex c3 = 2.71828 + c1;
Complex c4 = 2.71828 + 3.14159;
}
Compare overloads accepting double values directly, reducing conversions while preserving the intended arithmetic expressions. section 9.8
