Must read about C++ class type conversion operator summary of
- 2020-05-12 02:54:53
- OfStack
Examples are as follows:
class SmallInt {
public:
SmallInt(int i = 0): val(i)
{
if (i < 0 || i > 255)
throw std::out_of_range("Bad SmallInt initializer");
}
operator int() const { return val; }
private:
std::size_t val;
};
The transformation function takes the following general form:
operator type();
type represents a built-in type name, a class type name, or a name defined by a type alias. Conversion functions can be defined for any type that can be used as a function return type (except void). In general, converting to array or function types is not allowed, but to pointer types (data and function Pointers) and reference types is ok. The conversion function must be a member function, cannot specify a return type, and the parameter table must be empty. operator int returns an int value; If you define operator Sales_item, it will return an Sales_item object, and so on. Conversion function 1 should not change the object being converted. Therefore, the conversion operator should normally be defined as an const member.
SmallInt si;
double dval;
si > = dval // si converted to int and then convert todouble
Pros: class type conversion can be one of the benefits of implementing and using classes. It is easier to implement and use the SmallInt class by defining a transformation from SmallInt to int. The int transformation enables users of SmallInt to use all arithmetic and relational operators on SmallInt objects, and users can safely write expressions that mix SmallInt with other arithmetic types. Defining one conversion operator instead of defining 48 (or more) overloaded operators makes the job of the class implementor much easier.
Faults: 2 semantic
class SmallInt {
public:
SmallInt(int= 0);
SmallInt(double);
//Usually it is unwise to define conversions to multiple arithmetic types
operatorint() const { return val; }
operatordouble() const { return val; }
private:
std::size_tval;
};
void compute(int);
void fp_compute(double);
void extended_compute(long double);
SmallInt si;
compute(si); // SmallInt::operator int() const
fp_compute(si); // SmallInt::operator double() const
extended_compute(si); // error: ambiguous
The call to extended_compute is semantic. You can use any of the 1 conversion functions, but each must follow one of the standard conversions to get long double, so no one conversion is better than the others, and the call is semantic.
If both conversion operators are available in one call and a standard transformation exists after the conversion function, the best match is selected based on the category of the standard transformation. If there is no best match, the ambiguity occurs.
Such as:
There may be two conversion operators, or there may be two constructors that can be used to convert a value to a target type.
Consider the manip function, which accepts 1 argument of type SmallInt:
void manip(const SmallInt &);
double d; int i; long l;
manip(d); // ok: use SmallInt(double) to convert theargument
manip(i); // ok: use SmallInt(int) to convert theargument
manip(l); // error: ambiguous
The third call has a sense of 2. No constructor exactly matches long. Use each constructor
All arguments need to be converted before counting:
1. Standard conversion (from long to double) followed by SmallInt(double).
2. Standard conversion (from long to int) followed by SmallInt(int).
These conversion sequences are indistinguishable, so the call is semantic.
When two classes define a mutual transformation, it is likely that there is a sense of 2:
class Integral;
class SmallInt {
public:
SmallInt(Integral);// convert from Integral to SmallInt
};
class Integral {
public:
operatorSmallInt() const; // convert from Integral to SmallInt
};
void compute(SmallInt);
Integral int_val;
compute(int_val); // error: ambiguous
The argument int_val can be converted to an SmallInt object in two different ways that the compiler can use
You can also use the constructor that accepts the Integral object to convert the Integral object to
Integral conversion operation for SmallInt object. Because there's no difference between these two functions, so this
All calls will fail.
In this case, you can't use explicit type conversions to solve the problem of semantics -- explicit type conversions themselves can use both conversion operations and constructors; instead, you need to explicitly call the conversion operator or constructor:
compute(int_val.operator SmallInt()); // ok: useconversion operator
compute(SmallInt(int_val)); // ok: use SmallInt constructor
Change the constructor to accept the const Integral reference:
class SmallInt {
public:
SmallInt(constIntegral&);
};
The call to compute(int_val) is no longer binary! The reason is that using the SmallInt constructor requires binding a reference to int_val, and using the conversion operator of the Integral class avoids this extra step. This small difference is enough to make us prefer the conversion operator.
Explicit cast eliminates 2 semantics
class SmallInt {
public:
// Usually it is unwise to define conversions tomultiple
arithmetic types
operatorint() const { return val; }
operatordouble() const { return val; }
// ...
private:
std::size_tval;
};
void compute(int);
void compute(double);
void compute(long double);
SmallInt si;
compute(si); // error: ambiguous
You can use an explicit cast to eliminate 2 semantics:
compute(static_cast < int > (si)); // ok: convertand call compute(int)
Explicit constructor calls eliminate 2 semantics
class SmallInt {
public:
SmallInt(int= 0);
};
class Integral {
public:
Integral(int= 0);
};
void manip(const Integral&);
void manip(const SmallInt&);
manip(10); // error: ambiguous
You can eliminate 2 semantics with the display constructor:
manip(SmallInt(10)); // ok: call manip(SmallInt)
manip(Integral(10)); // ok: call manip(Integral)
Standard conversions are better than class type conversions
class LongDouble
{
public:
LongDouble(double );
// ...
};
void calc( int );
void calc( LongDouble );
double dval;
calc( dval ); // which function
The best available function is voidcalc(int), which is converted to: convert the argument double type to int type, which is the standard conversion; When the voidcalc(LongDouble) function is called, the argument is converted from double to LongDouble type, which is a class type conversion, because the standard conversion is better than the class type conversion, so the first function is the best feasible function.