C language performs implicit type conversions between standard data types.
The conversion rules are as follows:
- When converting from a smaller type to a larger one, the process is safe and automatic.
This implies that when a smaller data type is converted into a larger one, C supports implicit conversion, which is considered safe.
int main() { short s = 'a'; // Safe conversion from smaller to larger type unsigned int ui = 1000; // 1000 is default int, small to large type conversion int i = -2000; double d = i;
cout << d << endl;
if ((ui + i) > 0) // unsigned int + int ===> unsigned int + unsigned int > 0
{
cout << "Positive" << endl; // This will be printed
}
else
{
cout << "Negative" << endl;
}
cout << "sizeof(s + 'b')=" << sizeof(s + 'b') << endl; // Outputs 4, short + char ===> int + int, compiler prefers int for efficiency
return 0;
}
</div>2. Revisiting Constructors
--------------------------
Constructors can accept parameters of different types.
A constructor qualifies as a conversion constructor under these conditions:
1. It accepts exact one parameter.
2. The parameter is a basic data type.
3. The parameter is of another clas type.
Traditional C-style explicit casting:
<div>```
int i;
Test t;
i = int(1.5);
t = Test(100);
class Test { private: int mValue; public: Test() { mValue = 0; }
Test(int i)
{
mValue = i;
}
int value()
{
return mValue;
}
Test operator + (const Test& p)
{
Test ret(mValue + p.mValue);
return ret;
}
};
int main() { Test t; t = 100; // Compiler attempts to make the code compile // Since 100 is an int, compiler searches for a conversion constructor, finds Test(int) // Therefore, this is equivalent to t = Test(100)
cout << t.value() << endl; // Output: 100
Test tt;
tt = t + 10; // Is this intentional or a typo? A common source of bugs
cout << tt.value() << endl; // Output: 110
return 0;
}
</div>3. Preventing Implicit Type Conversion by the Compiler
------------------------------------------------------
In practice, use the `explicit` keyword to prevent automatic type conversions.
When a conversion constructor is marked with `explicit`, it can only be invoked explicitly.
Available conversion methods:
1. `static_cast<ClassName>(value)` – Recommended C++ approach
2. `ClassName(value)`
3. `(ClassName)value` – Not recommended
<div>```
#include <iostream>
using namespace std;
class Test
{
private:
int mValue;
public:
Test()
{
mValue = 0;
}
explicit Test(int i) // explicit keyword applied
{
mValue = i;
}
int value()
{
return mValue;
}
Test operator + (const Test& p)
{
Test ret(mValue + p.mValue);
return ret;
}
};
int main()
{
Test t;
t = static_cast<Test>(100); // Without explicit cast, compilation would fail
cout << t.value() << endl; // Output: 100
Test tt;
tt = t + static_cast<Test>(10);
cout << tt.value() << endl; // Output: 110
return 0;
}
- Conversion constructors take exactly one argument.
- The argument must be of a different type.
- These constructors are invoked during type conversion.
- Implicit conversion are often a significant source of bugs in real-world projects.
- The
explicitkeyword prevents unintended implicit conversions.