As we can invoke the explicit cast operator, using static_cast, a C-style cast, or a constructor style cast. I am confusing how exactly the operator interpret to these three casts.
For example, consider the following code. The const Money& balance
in display_balance()
can be cast to double in three ways. So what are these cast interpret. What I thought is there is only one explicit cast operator in Money, so the calling may would be balance.operator ()
. I really can't figure out how does the three different casting be interpreted.
class Money
{
public:
Money() : amount{ 0.0 } {};
Money(double _amount) : amount{ _amount } {};
explicit operator double() const { return amount; }
private:
double amount;
};
void display_balance(const Money& balance)
{
std::cout << "The balance is: " << (double)balance << "\n";
std::cout << "The balance is: " << double(balance) << "\n";
std::cout << "The balance is: " << static_cast<double>(balance) << "\n";
}
CodePudding user response:
Type Casting
It isn't the syntax you use when casting that determines how that cast is performed, it's the context based on the variable types.
When the compiler sees that you're trying to cast from Money
to double
, it tries to figure out a way to accomplish that - in every case, it uses the Money::operator double()
operator because in every case double
was specified as the target type.
C almost always allows you to accomplish one task in multiple different ways due to historical reasons; even its name alludes to its original goal: extending the C language.
Consider the following syntaxes:
Money balance(100.0);
// C-Style Cast
(double)balance; //< double with value 100.0
// Functional Cast
double(balance); //< double with value 100.0
double{ balance }; //< double with value 100.0
// Static Cast
static_cast<double>(balance); //< double with value 100.0
Once this is compiled, there isn't really any difference in which syntax you used; all of them call Money::operator double()
.
Of course, casting is always subject to operator precedence.
Note: While in this case all of the approaches are the same, this is not true in all cases.
Whenever possible, use static_cast
instead of c-style or functional casts - you can read more about why here.
Explicit vs. Implicit Type Casting
Consider the following objects:
Money
is your class.Cash
is a copy ofMoney
that allows implicit casting.
class Money
{
public:
Money() : amount{ 0.0 } {};
Money(double _amount) : amount{ _amount } {};
// This is an explicit casting operator:
explicit operator double() const { return amount; }
private:
double amount;
};
class Cash
{
public:
Cash() : amount{ 0.0 } {};
Cash(double _amount) : amount{ _amount } {};
// This is an implicit casting operator
operator double() const { return amount; }
private:
double amount;
};
Now consider the following function that accepts a double
:
void BuySomething(double amount) {}
In order to BuySomething()
with Money
, we must explicitly cast it to double
first:
Money money(500.0);
BuySomething(static_cast<double>(money));
BuySomething((double)money);
BuySomething(double(money));
BuySomething(double{ money });
// We can also just call the operator directly:
BuySomething(money.operator double());
However, we can BuySomething()
with Cash
without explicitly casting it first:
Cash cash(500.0);
BuySomething(cash);
// You can still use explicit casting:
BuySomething(static_cast<double>(cash));
BuySomething((double)cash);
BuySomething(double(cash));
BuySomething(double{ cash });
BuySomething(cash.operator double())
This is because when the compiler sees BuySomething(cash);
, it knows that BuySomething()
doesn't accept Cash
- it accepts double
- so rather than just throwing an error, it tries to figure out a way to convert Cash
to double
, and in the process finds our conversion operator.
If you notice something wrong with my explaination, let me know in the comments.