C++ performs “implicit conversions” between different types, such as silently converting char to int or int to char. “Implicit conversions” allow us to successfully provide a short or int to a function that requires a double.The above “implicit conversions” are provided by the language, and we cannot refuse them. However, C++ allows us to provide “implicit conversions” for our own classes in the following two ways:
- Single-parameter constructors, including constructors with multiple parameters but default values for all except the first parameter.
- Overloading the implicit type conversion operator.
class ID{public: // Single-parameter constructor, can implicitly convert int to ID ID(int id); // Multi-parameter constructor with default values for all but the first // Can implicitly convert int to ID ID(int id,int index = 0); // Overloaded implicit type conversion operator, can implicitly convert ID to int operator int() const;};
1. Do Not Provide Implicit Type ConversionsWhy is it advocated to follow the rule of not providing implicit type conversions? Because while “implicit conversions” provide us with convenience, they also bring greater problems.
// Created an id objectID id(1);// Print addition resultcout << add(id,1);
At this point, we expect “add(id,1)” to report an error, but in reality, the compiler will use “implicit conversion” to convert id to int and execute successfully. This contradicts our design intent and is difficult to correct.The situation provided in the example can be easily avoided, which is not to provide implicit type conversions. We can declare an explicit conversion function:
class ID{public: // Explicit conversion function int asInt();};
2. How to Prevent Implicit Conversions in Single-Parameter Constructors1. Using New C++ FeaturesActually, it’s not that new; the “explicit” keyword has been available since C++98 to prevent implicit conversions in single-parameter constructors. C++11 extended this feature to be used with multi-parameter constructors.
class ID{public: // Single-parameter constructor, cannot implicitly convert int to ID explicit ID(int id); // Multi-parameter constructor with default values for all but the first // Cannot implicitly convert int to ID explicit ID(int id,int index = 0);};// At this point, explicit conversion is allowedint num = 1;ID id = (ID)num;ID id1 = static_cast<ID>(num);
2. Old Method to Prevent Implicit Conversions in Single-Parameter ConstructorsThis actually utilizes the principle that “type conversion can only occur once at a time”:
class ID{public: // Nested class class IDNum{ public: // Single-parameter constructor IDNum(int num):num(num){} int getNum() const {return this->num;} private: int num; }; // Single-parameter constructor ID(IDNum id);};// Normal construction, will implicitly convert 1 from int to IDNumID id(1);// Error, 1 cannot be implicitly converted from int to IDNum, then to IDIDadd(id,1);
At this point, the constructor can be used normally. However, converting int to ID requires first converting to IDNum and then to ID. The compiler cannot perform two implicit conversion operations simultaneously.