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