C++类型转换 #

一、类型转换概述 #

类型转换是将一种数据类型的值转换为另一种数据类型的过程。C++支持两种类型转换:

  • 隐式类型转换:编译器自动进行
  • 显式类型转换:程序员明确指定

二、隐式类型转换 #

2.1 算术转换 #

cpp
// 整型提升
short s = 10;
int i = s;      // short → int

// 浮点提升
float f = 3.14f;
double d = f;   // float → double

// 混合运算时的转换
int a = 10;
double b = 3.14;
auto result = a + b;  // int → double,result是double

2.2 转换规则 #

cpp
// 转换方向:小类型 → 大类型
// char → short → int → long → long long → float → double → long double

// 混合运算示例
char c = 'A';
short s = 100;
int i = 1000;
long l = 10000;
float f = 3.14f;
double d = 3.14159;

auto r1 = c + s;    // int
auto r2 = i + l;    // long
auto r3 = f + d;    // double
auto r4 = i + f;    // float

2.3 赋值转换 #

cpp
int i = 10;
double d = i;     // int → double(安全)

double d2 = 3.14;
int i2 = d2;      // double → int(可能丢失精度,i2 = 3)

// 无符号转换
int neg = -1;
unsigned int pos = neg;  // 很大的正数(回绕)

2.4 布尔转换 #

cpp
// 非零值为true,零为false
int x = 10;
bool b1 = x;      // true

int y = 0;
bool b2 = y;      // false

double d = 3.14;
bool b3 = d;      // true

// 指针转布尔
int* ptr = nullptr;
bool b4 = ptr;    // false

int value = 10;
int* ptr2 = &value;
bool b5 = ptr2;   // true

三、C风格类型转换 #

3.1 基本语法 #

cpp
double d = 3.14;

// C风格转换
int i1 = (int)d;        // 3
int i2 = int(d);        // 3

// 问题:不安全,不推荐使用

3.2 C风格转换的问题 #

cpp
const int x = 10;
int* p = (int*)&x;  // 移除const,危险!

class Base {};
class Derived : public Base {};
class Other {};

Base* base = new Derived;
Other* other = (Other*)base;  // 完全不相关的类型转换,危险!

四、C++风格类型转换 #

C++提供了四种类型转换运算符,更加安全和明确。

4.1 static_cast #

用于相关类型之间的转换。

cpp
// 基本类型转换
double d = 3.14;
int i = static_cast<int>(d);  // 3

// 指针转换(相关类型)
void* ptr = &i;
int* p = static_cast<int*>(ptr);

// 类层次结构中的转换(编译时检查)
class Base { virtual void foo() {} };
class Derived : public Base {};

Base* base = new Derived;
Derived* derived = static_cast<Derived*>(base);  // 向下转型

// 不相关类型会编译错误
// int* p1 = static_cast<int*>(&d);  // 错误

4.2 dynamic_cast #

用于多态类型的安全向下转型。

cpp
class Base { 
public:
    virtual ~Base() {} 
};

class Derived : public Base {
public:
    void derivedMethod() { std::cout << "Derived method" << std::endl; }
};

int main() {
    Base* base = new Derived;
    
    // 安全的向下转型
    Derived* derived = dynamic_cast<Derived*>(base);
    if (derived) {
        derived->derivedMethod();
    }
    
    // 引用转型失败会抛出std::bad_cast异常
    try {
        Derived& ref = dynamic_cast<Derived&>(*base);
    } catch (const std::bad_cast& e) {
        std::cout << "Cast failed: " << e.what() << std::endl;
    }
    
    delete base;
    return 0;
}

4.3 const_cast #

用于移除或添加const属性。

cpp
const int x = 10;

// 移除const
int* p = const_cast<int*>(&x);
*p = 20;  // 未定义行为!不要修改原本的const变量

// 合法用途:调用非const版本的函数
void printString(const char* str) {
    // 某些旧API可能需要非const参数
    char* mutableStr = const_cast<char*>(str);
    // 使用mutableStr...
}

// 添加const
int y = 10;
const int* cp = const_cast<const int*>(&y);

4.4 reinterpret_cast #

用于不相关类型之间的低级转换。

cpp
// 指针与整数之间的转换
int x = 10;
long addr = reinterpret_cast<long>(&x);

// 不同指针类型之间的转换
int* pInt = &x;
char* pChar = reinterpret_cast<char*>(pInt);

// 函数指针转换
void (*func1)() = []() {};
int (*func2)() = reinterpret_cast<int(*)()>(func1);  // 危险!

// 注意:reinterpret_cast是危险的,慎用

五、类型转换对比 #

5.1 四种cast对比 #

转换类型 用途 安全性 运行时检查
static_cast 相关类型转换 中等
dynamic_cast 多态类型向下转型
const_cast 移除/添加const
reinterpret_cast 低级位转换 很低

5.2 选择指南 #

cpp
// 1. 基本类型转换 → static_cast
double d = 3.14;
int i = static_cast<int>(d);

// 2. 多态向下转型 → dynamic_cast
Base* base = new Derived;
Derived* derived = dynamic_cast<Derived*>(base);

// 3. 移除const → const_cast(谨慎使用)
const int* cp = &x;
int* p = const_cast<int*>(cp);

// 4. 底层位转换 → reinterpret_cast(尽量避免)
int* pInt = reinterpret_cast<int*>(&d);

六、类型转换函数 #

6.1 标准库转换函数 #

cpp
#include <string>

// 数值转字符串
std::string s1 = std::to_string(123);
std::string s2 = std::to_string(3.14);

// 字符串转数值
int i = std::stoi("123");
long l = std::stol("123456");
double d = std::stod("3.14");
float f = std::stof("3.14f");

6.2 自定义类型转换 #

cpp
class Fraction {
private:
    int numerator;
    int denominator;
    
public:
    Fraction(int n, int d) : numerator(n), denominator(d) {}
    
    // 转换为double
    operator double() const {
        return static_cast<double>(numerator) / denominator;
    }
    
    // 显式转换函数(C++11)
    explicit operator std::string() const {
        return std::to_string(numerator) + "/" + std::to_string(denominator);
    }
};

int main() {
    Fraction f(1, 2);
    
    double d = f;  // 隐式转换:0.5
    // std::string s = f;  // 错误:显式转换函数不能隐式调用
    std::string s = static_cast<std::string>(f);  // 正确
    
    return 0;
}

七、窄化转换 #

7.1 窄化转换问题 #

cpp
// 窄化转换:大类型 → 小类型,可能丢失数据
double d = 3.14;
int i = d;  // 窄化转换,i = 3

long l = 2147483648L;
int i2 = l;  // 窄化转换,可能溢出

7.2 使用列表初始化防止窄化转换 #

cpp
double d = 3.14;

// 普通初始化允许窄化转换
int i1 = d;  // 警告或无警告

// 列表初始化禁止窄化转换
int i2{d};   // 编译错误!
int i3 = {d}; // 编译错误!

// 正确做法
int i4 = static_cast<int>(d);
int i5{static_cast<int>(d)};

八、类型推导与转换 #

8.1 auto与类型转换 #

cpp
int x = 10;

// auto会丢弃引用和顶层const
const int& ref = x;
auto a = ref;        // int(丢弃const和引用)
const auto b = ref;  // const int

// auto不会丢弃底层const
const int* ptr = &x;
auto p = ptr;        // const int*

8.2 decltype与类型转换 #

cpp
const int x = 10;

// decltype保留所有类型信息
decltype(x) a = 20;  // const int

int& ref = x;
decltype(ref) b = x; // int&

九、最佳实践 #

9.1 避免C风格转换 #

cpp
// 不推荐
int i = (int)3.14;
int* p = (int*)malloc(100);

// 推荐
int i = static_cast<int>(3.14);
int* p = static_cast<int*>(malloc(100));
// 或更好的方式
int* p = new int[25];

9.2 优先使用安全转换 #

cpp
class Base { virtual ~Base() {} };
class Derived : public Base {};

Base* base = new Derived;

// 不推荐:不安全的向下转型
Derived* d1 = static_cast<Derived*>(base);

// 推荐:安全的向下转型
Derived* d2 = dynamic_cast<Derived*>(base);
if (d2) {
    // 安全使用
}

9.3 使用列表初始化 #

cpp
// 推荐:使用列表初始化防止窄化转换
int x{10};
double d{3.14};

// 需要转换时显式指定
int y{static_cast<int>(d)};

9.4 避免过度使用类型转换 #

cpp
// 类型转换可能表明设计问题
// 尽量使用多态、模板等替代

// 不好的设计
void process(void* data, int type) {
    if (type == 1) {
        int* p = static_cast<int*>(data);
        // ...
    } else if (type == 2) {
        double* p = static_cast<double*>(data);
        // ...
    }
}

// 好的设计:使用多态
class Data { virtual void process() = 0; };
class IntData : public Data { void process() override; };
class DoubleData : public Data { void process() override; };

十、总结 #

类型转换一览 #

转换方式 语法 用途
隐式转换 自动 安全的类型提升
C风格转换 (Type)value 不推荐
static_cast static_cast<Type>(value) 相关类型转换
dynamic_cast dynamic_cast<Type>(value) 多态向下转型
const_cast const_cast<Type>(value) 移除const
reinterpret_cast reinterpret_cast<Type>(value) 低级转换

最佳实践 #

  1. 优先使用C++风格的类型转换
  2. 使用列表初始化防止窄化转换
  3. 多态类型使用dynamic_cast
  4. 避免使用reinterpret_cast
  5. 设计良好的类型系统,减少类型转换需求

下一步,让我们学习输入输出!

最后更新:2026-03-26