[ fromfile: conversions.xml id: conversions ]
A constructor that can be called with a single argument (of a different type) is a conversion constructor because it defines a conversion from the argument type to the constructor's class type.
Example 2.19. src/ctor/conversion/fraction.cpp
class Fraction { public: Fraction(int n) : m_Numer(n), m_Denom(1) {} Fraction(int n, int d ) : m_Numer(n), m_Denom(d) {} Fraction times(const Fraction& other) { return Fraction(m_Numer * other.m_Numer, m_Denom * other.m_Denom); } private: int m_Numer, m_Denom; }; int main() { int i; Fraction frac(8); Fraction frac2 = 5; frac = 9; frac = (Fraction) 7; frac = Fraction(6); frac = static_cast<Fraction>(6); frac = frac2.times(19); return 0; }
Single argument ctor defines a conversion from int. | |
Conversion constructor call. | |
Copy init (calls conversion ctor too). | |
Conversion followed by assignment. | |
C-style typecast (deprecated). | |
Explicit temporary, also a C++ typecast. | |
Preferred ANSI style typecast. | |
Implicit call to the conversion constructor. |
<include src="src/ctor/conversion/fraction.cpp" href="src/ctor/conversion/fraction.cpp" id="fractioncppconv" mode="cpp"/>
In the main()
function of Example 2.19, the Fraction
variable frac
is initialized with a single int
.
The matching constructor is the one-parameter version.
Effectively, it converts the integer 8
to the fraction 8/1
.
The prototype for a conversion constructor typically looks like this:
ClassA::ClassA(const ClassB& bobj);
The conversion constructor for ClassA is automatically called when an object of that class is required, and when such an object can be created by that constructor from the value of ClassB that was supplied as an initializer or assigned value.
For example, if frac
is a properly initialized Fraction
as defined in Example 2.19, you can write the statement
frac = frac.times(19);
Because 19
is not a Fraction
object (as required by the times()
function definition), the compiler checks to see whether it can be converted to a Fraction
.
Because you have a conversion constructor, this is indeed possible.
Fraction::operator=()
is not defined, so the compiler uses a default assignment operator that it supplied:
Fraction& operator=(const Fraction& fobj);
This assignment operator performs a memberwise assignment, from each data member of fobj
to the corresponding member of the host object.
So, that statement calls three Fraction
member functions:
Fraction::operator=()
to perform the assignment.
Fraction::times()
to perform the multiplication.
Fraction::Fraction(19)
to convert 19
from int
to Fraction
.
The temporary Fraction
object returned by the times()
function exists just long enough to complete the assignment and is then automatically destroyed.
You can simplify the class definition for Fraction
by eliminating the one-parameter constructor and providing a default value for the second parameter of the two-parameter constructor.
Because it can be called with only one argument, it satisfies the definition of conversion constructor.
Example 2.20. src/ctor/conversion/fraction.h
class Fraction { public: Fraction(int n, int d = 1) : m_Numer(n), m_Denom(d) {} Fraction times(const Fraction& other) { return Fraction(m_Numer* other.m_Numer, m_Denom* other.m_Denom); } private: int m_Numer, m_Denom; };
<include src="src/ctor/conversion/fraction.h" href="src/ctor/conversion/fraction.h" id="fractionhconv" mode="cpp"/>
Ordinarily, any constructor that can be called with a single argument of a different type is a conversion constructor that has the implicit mechanisms discussed above.
If the implicit mechanisms are not appropriate for some reason, it is possible to suppress them.
The keyword explicit
prevents the compiler from automatically using that constructor for implicit conversions. [32]
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |