Before understanding an explicit constructor, first check-out case of implicit constructor. A constructor which takes parameter of specific type, allows automatic conversion from given to the constructor type. This is called implicit conversion and the constructor becomes implicit constructor.
The implicit constructor may lead to unexpected results.
#include <iostream> //main header
using namespace std;//for namespace
class MFFraction
{
int numerator;
int denominator;
public:
MFFraction(int num, int den=1) :
numerator(num),
denominator(den)
{
cout << "Constructor called for Fraction : "
<< numerator
<< "/"
<< denominator
<< endl;
}
int getNum() { return numerator; }
int getDen() { return denominator; }
};
MFFraction operator*( MFFraction first, MFFraction second)
{
int resultNum = first.getNum() * second.getNum();
int resultDen = first.getDen() * second.getDen();
return MFFraction(resultNum, resultDen);
}
int main()
{
MFFraction first(1, 3);
MFFraction result = first * 2;
//implicit construction for 2
return 0;
}
The output is:
Constructor called for Fraction : 1/3
Constructor called for Fraction : 2/1
Constructor called for Fraction : 2/3
Clearly, constructor call for object “first” was done knowingly.
Similar, is the constructor call for object “result”.
However, for object “second”, the constructor call happened implicitly, because the class Fraction allows construction with atleast one integer.
The value 2 got converted to a temporary object due to implicit constructor.
MFFraction result = first * 2;
Explanation of Explicit Constructor
To stop this automatic conversion, the class should use explicit constructor.
Here, constructor is preceded by explicit keyword, this will not allow the C++ compilation to complete in such cases.
explicit MFFraction(int num, int den=1) :
numerator(num),
denominator(den)
{
cout << "Constructor called for Fraction : "
<< numerator
<< "/"
<< denominator
<< endl;
}
What are the problems with implicit constructors
Too many Implicit constructors in different classes may sometimes cause ambiguity.
Example, when the program has a second class Integer and that class also contains an implicit constructor. This implicit constructor also takes an integer parameter (in the same way as Fraction class),
class MFInteger
{
int number;
public:
MFInteger(int num): number(num)
{
cout << "MFInteger::MFInteger()" << endl;
}
int getNum() { return number; }
int setNum(int x) { number = x; }
};
Now both classes cannot work together because, an integer value (like, 2) can be converted to either MFFraction or to MFInteger and compiler cannot take a decision.
void PrintNumber(MFInteger r)
{
cout << "PrintNumber(MFInteger)" << endl;
}
void PrintNumber(MFFraction r)
{
cout << "PrintNumber(MFFraction)" << endl;
}
int main()
{
PrintNumber(2); //Ambiguous call
return 0;
}
Making the constructors explicit may give one way to solve the problems like, this.