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.


Related articles: