Consider following example:
#include <iostream>
using std::cout;
using std::endl;
class CBox
{
public:
CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0) :
m_Length {lv}, m_Width {wv}, m_Height {hv}
{
cout << "Constructor called" << endl;
}
//CBox& operator=(double)
//{
// cout << "Assignment operator called" << endl;
// return *this;
//}
double volume() const { return m_Length* m_Width* m_Height; }
private:
double m_Length;
double m_Width;
double m_Height;
};
int main()
{
CBox box {1.0, 1.0, 1.0}; // no need for initializer list, but put it anyway
box = 2.0; // why is this calling constructor again ?!
cout << box.volume() << endl; // prints 2
}
Note, that I intentionally commented out the overloaded assignment operator.
Executing this program results in following output:
Constructor called
Constructor called
2
I noticed, that even if box
object has been initialized, the next statement is deliberately calling the constructor again. What is the point of that?
I know that this can prevented by the explicit
keyword, so the constructor would be:
explicit CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0) :
m_Length {lv}, m_Width {wv}, m_Height {hv}
{
cout << "Constructor called" << endl;
}
but I would rather expect it to affect constructs like:
CBox box = 2.0;
Of course, when I uncomment overloaded assignment operator, then it takes precedence over constructor.
There is no implicit CBox::operator=(double)
, so box = 2.0;
has to create a temporary CBox
object. It's equivalent to box = CBox(2.0);
.
Making your constructor explicit
disallows the implicit conversion from double
to CBox
, so no appropriate assignment operator exists, and you get a compile error.
There is a great difference between
CBox box = 2.0
and
box = 2.0
The first is equivalent to
CBox box = CBox(2.0)
While the second is equivalent to
box.operator=(2.0)
Since your constructor's arguments have default values, this is equivalent to defining 3 different constructors:
CBox(double, double, double)
CBox(double, double) // the third arguments gets default value
CBox(double) // second and third arguments gets default values
So, calling the constructor explicitly with a single double
will invoke your constructor and will give the second and third arguments default values. And now for the real mystery: why did calling the operator=
eventually result in calling a constructor?
Since you don't have an explicitly defined operator=
, the compiler will auto-generate an assignment operator that takes another CBox
as its single parameter; this will make a copy of the argument.
When you try to assign anything into your CBox
object the compiler will attempt to call operator=(const CBox&)
; since you provide a double
and not a CBox
, the compiler will try to convert the double into a CBox
in one of many possible ways:
So, eventually this code:
box = 2.0
will be translated to:
box.operator=(Cbox(2.0))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With