Overloading typecasts is used to enable program defined types such as classes or structs to implicit or explicit convertible to another type. For fundamental types, C++ knows how to do implicit and explicit conversions but for program defined types, we need to define the conversion.
For example, if we have a class Int and we think that it should be able to convert to fundamental type int, we need to overload int typecast to let compiler know about the conversion.
Following shows code Int example:
#include <iostream>
class Int
{
int m_value{};
public:
Int() = default;
Int(int value)
: m_value{value}
{
}
operator int() const
{
return m_value;
}
friend std::ostream &operator<<(std::ostream &out, const Int &v)
{
return out << v.m_value;
}
};
void print(int i)
{
std::cout << i << '\n';
}
int main(int argc, char const *argv[])
{
Int v{1};
print(v);
return 0;
}So here, we add member function operator int() to overload typecast. This is the way typecast overload function are created and following are few points about it:
- It always has to be a non-static member function.
- It starts with
operatorand then target type name. - This function should not have any parameters.
- It also does not have return type because target type name is already mentioned as function name.
So, when we pass v to print which accepts int, compiler would implicitly convert v to int using the overloaded typecast operator.
For this example, we have overloaded typecast operator for int but we can do it for other types (including program defined type) as well.
We could also use static_cast to explicitly convert Int to int as shown below:
print(static_cast<int>(v));Note
This can look a bit similar to converting constructors where a value of one type get implicitly converted to class object using the constructor, where the class object is required. For example, passing a
intvalue to a function expecting aIntargument. AsInthas a constructor which acceptsintargument,intimplicitly gets converted toIntusing that constructor.
Explicit typecasts
If implicit conversion is not intended, we can make them explicit (as we do with explicit constructors). We still can use static_cast for explicit conversion.
For example:
#include <iostream>
class Int
{
int m_value{};
public:
Int() = default;
Int(int value)
: m_value{value}
{
}
explicit operator int() const
{
return m_value;
}
friend std::ostream &operator<<(std::ostream &out, const Int &v)
{
return out << v.m_value;
}
};
void printInt(Int i)
{
std::cout << i << '\n';
}
void print(int i)
{
std::cout << i << '\n';
}
int main(int argc, char const *argv[])
{
Int v{1};
// print(v); // will not work
print(static_cast<int>(v));
return 0;
}So, print(v) would not work as typecast overload is explicit.
It is advisable to make overload typecast explicit unless it really makes sense. For example, it makes sense for Int to be implicitly converted to int.