不熟悉默认类型转换,真的很容易写出bug!!!
在C++中,类型转换是一个非常重要的概念。下面详细讲解C++中各种默认类型转换的规则和机制。
1. 算术类型转换
整型提升 (Integral Promotion)
1char c = 'A'; 2short s = 100; 3int i = c + s; // char和short都提升为int 4
算术转换规则
1// 转换优先级:long double > double > float > unsigned long long > long long > 2// unsigned long > long > unsigned int > int 3 4int i = 10; 5double d = 3.14; 6double result = i + d; // int转换为double 7 8unsigned int u = 100; 9int j = -50; 10unsigned int result2 = u + j; // int转换为unsigned int 11
2. 指针类型转换
隐式指针转换
1// 派生类指针到基类指针 2class Base {}; 3class Derived : public Base {}; 4 5Derived d; 6Base* bp = &d; // 隐式向上转换 7 8// 数组到指针退化 9int arr[5]; 10int* ptr = arr; // 数组退化为指针 11 12// 0或nullptr到指针 13int* p1 = 0; 14int* p2 = nullptr; 15 16// 任意指针到void* 17int x = 10; 18void* vp = &x; 19
3. 引用类型转换
1class Base { 2public: 3 virtual void show() { cout << "Base" << endl; } 4}; 5 6class Derived : public Base { 7public: 8 void show() override { cout << "Derived" << endl; } 9}; 10 11Derived d; 12Base& br = d; // 派生类引用到基类引用 13br.show(); // 输出: Derived (多态) 14
4. 限定符转换 (Qualification Conversions)
const转换
1int x = 10; 2const int* cp = &x; // 非const到const 3// int* p = cp; // 错误: 不能去掉const限定 4 5const int y = 20; 6// int* p2 = &y; // 错误: 不能去掉const限定 7const int* cp2 = &y; // OK 8
volatile转换
1int normal = 10; 2volatile int vi = 20; 3volatile int* vp = &normal; // 非volatile到volatile 4// int* p = &vi; // 错误: 不能去掉volatile限定 5
5. 布尔转换
1// 以下情况会隐式转换为bool 2int* ptr = nullptr; 3if (ptr) { // 指针到bool: nullptr→false, 其他→true 4 cout << "Pointer is valid" << endl; 5} 6 7int value = 10; 8if (value) { // 算术类型到bool: 0→false, 非0→true 9 cout << "Value is non-zero" << endl; 10} 11
6. 用户定义类型转换
转换构造函数
1class MyString { 2private: 3 char* str; 4public: 5 // 转换构造函数: const char* → MyString 6 MyString(const char* s) { 7 str = new char[strlen(s) + 1]; 8 strcpy(str, s); 9 } 10 11 ~MyString() { delete[] str; } 12}; 13 14MyString s = "Hello"; // 隐式调用转换构造函数 15
类型转换运算符
1class SmartBool { 2private: 3 bool value; 4public: 5 SmartBool(bool b) : value(b) {} 6 7 // 类型转换运算符: SmartBool → bool 8 operator bool() const { 9 return value; 10 } 11}; 12 13SmartBool sb = true; 14if (sb) { // 隐式调用operator bool() 15 cout << "SmartBool is true" << endl; 16} 17
7. 标准转换序列
C++编译器会尝试以下标准转换序列:
1class A {}; 2class B : public A {}; 3class C {}; 4 5void func(A a) {} 6 7int main() { 8 B b; 9 func(b); // 标准转换: B → A (派生类到基类) 10 11 // 可能的转换序列: 12 // 1. 精确匹配 13 // 2. 提升转换 14 // 3. 标准转换 15 // 4. 用户定义转换 16 // 5. 省略号匹配 17} 18
8. 显式控制隐式转换
explicit关键字
1class ExplicitClass { 2public: 3 explicit ExplicitClass(int x) {} // 禁止隐式转换 4}; 5 6void test(ExplicitClass ec) {} 7 8int main() { 9 // ExplicitClass ec = 10; // 错误: 不能隐式转换 10 ExplicitClass ec(10); // OK: 直接初始化 11 test(ExplicitClass(10)); // OK: 显式转换 12} 13
删除转换函数
1class NoConvert { 2public: 3 NoConvert(int) {} 4 5 // 删除不需要的转换 6 NoConvert(double) = delete; 7 operator bool() = delete; 8}; 9 10NoConvert nc(10); // OK 11// NoConvert nc(3.14); // 错误: 使用已删除的函数 12// if (nc) {} // 错误: 使用已删除的函数 13
9. 转换的优先级和歧义
1class Ambiguous { 2public: 3 Ambiguous(int x) {} 4 Ambiguous(double x) {} 5}; 6 7void func(Ambiguous a) {} 8 9int main() { 10 // func(10); // 歧义: int可以转换为int或double 11 func(Ambiguous(10)); // 必须显式指定 12} 13
10. 最佳实践和注意事项
- 避免意外的隐式转换
1// 使用explicit防止意外的构造函数转换 2// 小心算术类型转换的精度损失
- 注意符号性和大小
1unsigned int u = 10; 2int i = -5; 3if (u > i) { // i转换为unsigned int, 结果可能出乎意料 4 cout << "Unexpected result!" << endl; 5}
- 使用static_cast进行显式转换
1double d = 3.14; 2int i = static_cast<int>(d); // 明确的意图
理解C++的类型转换规则对于编写安全、高效的代码至关重要。在可能产生歧义或意外行为的地方,建议使用显式转换来明确意图。
《C++中不同类型的默认转换详解》 是转载文章,点击查看原文。
