C++学习笔记-类型转换

C++提供了多种类型转换方式,包括C风格转换和C++风格转换。C++风格转换更加安全和明确,包括static_cast、dynamic_cast、const_cast和reinterpret_cast四种。动态类型转换提供了运行时类型检查,确保转换的有效性。

C风格转换 vs C++风格转换

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>

class Entity
{
public:
    int x, y;
    Entity() : x(0), y(0) {}
    Entity(int x, int y) : x(x), y(y) {}

    virtual void Print() {} // 动态类型转换需要一个虚函数类型,所以需要一个虚函数,这里随便写了一个虚函数
};

class Player : public Entity 
{
public:
    Player() = default;
    Player(int x, int y) : Entity(x, y) {}
};

class Enemy : public Entity
{
public:
    Enemy() = default;
    Enemy(int x, int y) : Entity(x, y) {}
};

int main()
{
    Entity e = {5, 8};
    double value = 5.25;

    std::cout << "=== C-style vs C++-style Casting ===" << std::endl;
    
    /* C风格的类型转换 */
    double a = (int)value + 5.3; // 一般类型转换
    int* array1 = (int*)&e; // 类型双关
    
    /* C++风格的类型转换 */
    double b = static_cast<int>(value) + 5.3; // 一般类型转换
    int* array2 = reinterpret_cast<int*>(&e); // 类型双关

    std::cout << "C-style cast result: " << a << std::endl;
    std::cout << "C++ static_cast result: " << b << std::endl;
    
    // 访问Entity的成员作为int数组
    std::cout << "Entity x through C-style cast: " << array1[0] << std::endl;
    std::cout << "Entity y through C-style cast: " << array1[1] << std::endl;
    std::cout << "Entity x through reinterpret_cast: " << array2[0] << std::endl;
    std::cout << "Entity y through reinterpret_cast: " << array2[1] << std::endl;

    return 0;
}

static_cast - 静态类型转换

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>

class Base
{
public:
    virtual ~Base() = default;
    virtual void Print() { std::cout << "Base" << std::endl; }
};

class Derived : public Base
{
public:
    void Print() override { std::cout << "Derived" << std::endl; }
    void SpecialFunction() { std::cout << "Special function in Derived" << std::endl; }
};

void StaticCastDemo()
{
    std::cout << "=== static_cast Demo ===" << std::endl;
    
    // 1. 基本类型转换
    int intValue = 42;
    double doubleValue = static_cast<double>(intValue);
    std::cout << "int to double: " << intValue << " -> " << doubleValue << std::endl;
    
    float floatValue = 3.14159f;
    int truncatedValue = static_cast<int>(floatValue);
    std::cout << "float to int: " << floatValue << " -> " << truncatedValue << std::endl;
    
    // 2. 指针类型转换(继承层次中)
    Derived* derived = new Derived();
    Base* base = static_cast<Base*>(derived);  // 向上转换(安全)
    base->Print();
    
    // 向下转换(需要确保类型正确)
    Base* basePtr = new Derived();
    Derived* derivedPtr = static_cast<Derived*>(basePtr);  // 程序员保证类型正确
    derivedPtr->SpecialFunction();
    
    // 3. void*转换
    void* voidPtr = derived;
    Derived* backToDerived = static_cast<Derived*>(voidPtr);
    backToDerived->Print();
    
    // 4. 枚举转换
    enum Color { RED = 1, GREEN = 2, BLUE = 3 };
    int colorValue = static_cast<int>(RED);
    Color color = static_cast<Color>(2);
    std::cout << "Enum to int: " << colorValue << std::endl;
    std::cout << "Int to enum: " << color << " (GREEN)" << std::endl;
    
    delete derived;
    delete basePtr;
}

int main()
{
    StaticCastDemo();
    return 0;
}

dynamic_cast - 动态类型转换

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <iostream>
#include <typeinfo>

class Animal
{
public:
    virtual ~Animal() = default;
    virtual void MakeSound() = 0;
    virtual void Print() { std::cout << "Animal"; }
};

class Dog : public Animal
{
public:
    void MakeSound() override { std::cout << "Woof!" << std::endl; }
    void Print() override { std::cout << "Dog"; }
    void Fetch() { std::cout << "Dog is fetching!" << std::endl; }
};

class Cat : public Animal
{
public:
    void MakeSound() override { std::cout << "Meow!" << std::endl; }
    void Print() override { std::cout << "Cat"; }
    void Climb() { std::cout << "Cat is climbing!" << std::endl; }
};

class Bird : public Animal
{
public:
    void MakeSound() override { std::cout << "Tweet!" << std::endl; }
    void Print() override { std::cout << "Bird"; }
    void Fly() { std::cout << "Bird is flying!" << std::endl; }
};

void DynamicCastDemo()
{
    std::cout << "=== dynamic_cast Demo ===" << std::endl;
    
    // 创建不同类型的动物
    Animal* animals[] = {
        new Dog(),
        new Cat(),
        new Bird(),
        new Dog()
    };
    
    for (int i = 0; i < 4; ++i)
    {
        std::cout << "\nAnimal " << i << ": ";
        animals[i]->Print();
        std::cout << std::endl;
        animals[i]->MakeSound();
        
        // 尝试转换为Dog
        Dog* dog = dynamic_cast<Dog*>(animals[i]);
        if (dog) // 动态类型转换可以运行时验证,如果转换后的指针无效时,会返回NULL也就是0
        {
            std::cout << "  This is a dog! ";
            dog->Fetch();
        }
        
        // 尝试转换为Cat
        Cat* cat = dynamic_cast<Cat*>(animals[i]);
        if (cat)
        {
            std::cout << "  This is a cat! ";
            cat->Climb();
        }
        
        // 尝试转换为Bird
        Bird* bird = dynamic_cast<Bird*>(animals[i]);
        if (bird)
        {
            std::cout << "  This is a bird! ";
            bird->Fly();
        }
    }
    
    // 清理内存
    for (auto* animal : animals)
    {
        delete animal;
    }
}

// 引用的dynamic_cast
void DynamicCastWithReferences()
{
    std::cout << "\n=== dynamic_cast with References ===" << std::endl;
    
    Dog dog;
    Animal& animalRef = dog;
    
    try
    {
        Dog& dogRef = dynamic_cast<Dog&>(animalRef);
        std::cout << "Successfully cast to Dog reference" << std::endl;
        dogRef.Fetch();
    }
    catch (const std::bad_cast& e)
    {
        std::cout << "Failed to cast to Dog reference: " << e.what() << std::endl;
    }
    
    try
    {
        Cat& catRef = dynamic_cast<Cat&>(animalRef);
        std::cout << "Successfully cast to Cat reference" << std::endl;
        catRef.Climb();
    }
    catch (const std::bad_cast& e)
    {
        std::cout << "Failed to cast to Cat reference: " << e.what() << std::endl;
    }
}

int main()
{
    DynamicCastDemo();
    DynamicCastWithReferences();
    return 0;
}

const_cast - 常量转换

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <iostream>
#include <cstring>

void ModifyString(char* str)
{
    // 修改字符串的函数(需要非const指针)
    for (int i = 0; str[i] != '\0'; ++i)
    {
        if (str[i] >= 'a' && str[i] <= 'z')
        {
            str[i] = str[i] - 'a' + 'A';  // 转换为大写
        }
    }
}

void PrintValue(const int& value)
{
    std::cout << "Value: " << value << std::endl;
}

void ConstCastDemo()
{
    std::cout << "=== const_cast Demo ===" << std::endl;
    
    // 1. 移除const限定符
    const char* constStr = "hello world";
    char buffer[20];
    strcpy(buffer, constStr);
    
    // 需要调用需要非const参数的函数
    char* nonConstStr = const_cast<char*>(buffer);
    std::cout << "Before: " << buffer << std::endl;
    ModifyString(nonConstStr);
    std::cout << "After: " << buffer << std::endl;
    
    // 2. 添加const限定符
    int value = 42;
    int* ptr = &value;
    const int* constPtr = const_cast<const int*>(ptr);
    std::cout << "Original value: " << *ptr << std::endl;
    std::cout << "Through const pointer: " << *constPtr << std::endl;
    
    // 3. 移除const以修改值(危险操作)
    const int constValue = 100;
    int* modifiablePtr = const_cast<int*>(&constValue);
    
    std::cout << "Original const value: " << constValue << std::endl;
    *modifiablePtr = 200;  // 未定义行为!
    std::cout << "After modification: " << constValue << std::endl;
    std::cout << "Through pointer: " << *modifiablePtr << std::endl;
    
    // 4. 实际应用:与C API交互
    const char* filename = "data.txt";
    // 某些C函数可能需要char*但实际不修改内容
    char* cFilename = const_cast<char*>(filename);
    std::cout << "Filename: " << cFilename << std::endl;
}

// 实际应用:缓存系统
class Cache
{
private:
    mutable std::string m_CachedData;
    mutable bool m_IsCached;
    
public:
    Cache() : m_IsCached(false) {}
    
    const std::string& GetData() const
    {
        if (!m_IsCached)
        {
            // 在const函数中修改mutable成员
            m_CachedData = "Expensive computation result";
            m_IsCached = true;
            std::cout << "Data computed and cached" << std::endl;
        }
        else
        {
            std::cout << "Data retrieved from cache" << std::endl;
        }
        return m_CachedData;
    }
    
    // 如果没有mutable,可能需要const_cast
    void ClearCache() const
    {
        // 这是一个不好的例子,应该使用mutable
        Cache* nonConstThis = const_cast<Cache*>(this);
        nonConstThis->m_IsCached = false;
        nonConstThis->m_CachedData.clear();
        std::cout << "Cache cleared" << std::endl;
    }
};

void CacheDemo()
{
    std::cout << "\n=== Cache Demo ===" << std::endl;
    
    const Cache cache;
    
    std::cout << "First access: " << cache.GetData() << std::endl;
    std::cout << "Second access: " << cache.GetData() << std::endl;
    
    cache.ClearCache();
    std::cout << "After clear: " << cache.GetData() << std::endl;
}

int main()
{
    ConstCastDemo();
    CacheDemo();
    return 0;
}

reinterpret_cast - 重新解释转换

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <iostream>
#include <cstdint>

struct Point
{
    int x, y;
    Point(int x, int y) : x(x), y(y) {}
};

struct Color
{
    uint8_t r, g, b, a;
    Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255) : r(r), g(g), b(b), a(a) {}
};

void ReinterpretCastDemo()
{
    std::cout << "=== reinterpret_cast Demo ===" << std::endl;
    
    // 1. 指针类型之间的转换
    Point point(10, 20);
    int* intPtr = reinterpret_cast<int*>(&point);
    
    std::cout << "Point: (" << point.x << ", " << point.y << ")" << std::endl;
    std::cout << "As int array: [" << intPtr[0] << ", " << intPtr[1] << "]" << std::endl;
    
    // 修改通过int指针
    intPtr[0] = 100;
    intPtr[1] = 200;
    std::cout << "Modified Point: (" << point.x << ", " << point.y << ")" << std::endl;
    
    // 2. 整数和指针之间的转换
    uintptr_t address = reinterpret_cast<uintptr_t>(&point);
    std::cout << "Point address as integer: 0x" << std::hex << address << std::dec << std::endl;
    
    Point* pointPtr = reinterpret_cast<Point*>(address);
    std::cout << "Back to pointer: (" << pointPtr->x << ", " << pointPtr->y << ")" << std::endl;
    
    // 3. 不同结构体之间的转换(危险)
    Color color(255, 128, 64, 255);
    uint32_t* colorAsInt = reinterpret_cast<uint32_t*>(&color);
    
    std::cout << "Color RGBA: (" << (int)color.r << ", " << (int)color.g 
              << ", " << (int)color.b << ", " << (int)color.a << ")" << std::endl;
    std::cout << "Color as uint32: 0x" << std::hex << *colorAsInt << std::dec << std::endl;
    
    // 4. 函数指针转换
    void (*funcPtr)() = reinterpret_cast<void(*)()>(0x12345678);
    std::cout << "Function pointer: " << reinterpret_cast<void*>(funcPtr) << std::endl;
    
    // 5. 字节级别的数据访问
    double pi = 3.14159265359;
    uint64_t* piAsInt = reinterpret_cast<uint64_t*>(&pi);
    
    std::cout << "Pi: " << pi << std::endl;
    std::cout << "Pi as uint64: 0x" << std::hex << *piAsInt << std::dec << std::endl;
    
    // 分析IEEE 754格式
    uint8_t* bytes = reinterpret_cast<uint8_t*>(&pi);
    std::cout << "Pi bytes: ";
    for (int i = 0; i < 8; ++i)
    {
        std::cout << "0x" << std::hex << (int)bytes[i] << " ";
    }
    std::cout << std::dec << std::endl;
}

// 实际应用:序列化
class Serializer
{
public:
    template<typename T>
    static void SerializePOD(const T& obj, uint8_t* buffer)
    {
        static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable");
        
        const uint8_t* objBytes = reinterpret_cast<const uint8_t*>(&obj);
        for (size_t i = 0; i < sizeof(T); ++i)
        {
            buffer[i] = objBytes[i];
        }
    }
    
    template<typename T>
    static T DeserializePOD(const uint8_t* buffer)
    {
        static_assert(std::is_trivially_copyable_v<T>, "Type must be trivially copyable");
        
        T obj;
        uint8_t* objBytes = reinterpret_cast<uint8_t*>(&obj);
        for (size_t i = 0; i < sizeof(T); ++i)
        {
            objBytes[i] = buffer[i];
        }
        return obj;
    }
};

void SerializationDemo()
{
    std::cout << "\n=== Serialization Demo ===" << std::endl;
    
    Point originalPoint(42, 84);
    uint8_t buffer[sizeof(Point)];
    
    // 序列化
    Serializer::SerializePOD(originalPoint, buffer);
    
    std::cout << "Original point: (" << originalPoint.x << ", " << originalPoint.y << ")" << std::endl;
    std::cout << "Serialized bytes: ";
    for (size_t i = 0; i < sizeof(Point); ++i)
    {
        std::cout << "0x" << std::hex << (int)buffer[i] << " ";
    }
    std::cout << std::dec << std::endl;
    
    // 反序列化
    Point deserializedPoint = Serializer::DeserializePOD<Point>(buffer);
    std::cout << "Deserialized point: (" << deserializedPoint.x << ", " << deserializedPoint.y << ")" << std::endl;
}

int main()
{
    ReinterpretCastDemo();
    SerializationDemo();
    return 0;
}

类型转换的最佳实践

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <iostream>
#include <memory>
#include <vector>

class Shape
{
public:
    virtual ~Shape() = default;
    virtual void Draw() const = 0;
    virtual double GetArea() const = 0;
};

class Circle : public Shape
{
private:
    double m_Radius;
    
public:
    Circle(double radius) : m_Radius(radius) {}
    
    void Draw() const override
    {
        std::cout << "Drawing circle with radius " << m_Radius << std::endl;
    }
    
    double GetArea() const override
    {
        return 3.14159 * m_Radius * m_Radius;
    }
    
    double GetRadius() const { return m_Radius; }
};

class Rectangle : public Shape
{
private:
    double m_Width, m_Height;
    
public:
    Rectangle(double width, double height) : m_Width(width), m_Height(height) {}
    
    void Draw() const override
    {
        std::cout << "Drawing rectangle " << m_Width << "x" << m_Height << std::endl;
    }
    
    double GetArea() const override
    {
        return m_Width * m_Height;
    }
    
    double GetWidth() const { return m_Width; }
    double GetHeight() const { return m_Height; }
};

void BestPracticesDemo()
{
    std::cout << "=== Type Casting Best Practices ===" << std::endl;
    
    std::vector<std::unique_ptr<Shape>> shapes;
    shapes.push_back(std::make_unique<Circle>(5.0));
    shapes.push_back(std::make_unique<Rectangle>(4.0, 6.0));
    shapes.push_back(std::make_unique<Circle>(3.0));
    
    for (const auto& shape : shapes)
    {
        shape->Draw();
        std::cout << "Area: " << shape->GetArea() << std::endl;
        
        // 好的做法:使用dynamic_cast进行安全的向下转换
        if (auto circle = dynamic_cast<Circle*>(shape.get()))
        {
            std::cout << "  This is a circle with radius: " << circle->GetRadius() << std::endl;
        }
        else if (auto rectangle = dynamic_cast<Rectangle*>(shape.get()))
        {
            std::cout << "  This is a rectangle: " << rectangle->GetWidth() 
                      << " x " << rectangle->GetHeight() << std::endl;
        }
        
        std::cout << std::endl;
    }
}

// 类型转换指南
void CastingGuidelines()
{
    std::cout << "=== Casting Guidelines ===" << std::endl;
    
    std::cout << "1. static_cast:" << std::endl;
    std::cout << "   - 基本类型转换" << std::endl;
    std::cout << "   - 继承层次中的向上转换" << std::endl;
    std::cout << "   - 明确的向下转换(程序员保证安全)" << std::endl;
    std::cout << "   - void*转换" << std::endl;
    
    std::cout << "\n2. dynamic_cast:" << std::endl;
    std::cout << "   - 安全的向下转换(运行时检查)" << std::endl;
    std::cout << "   - 需要虚函数表(RTTI)" << std::endl;
    std::cout << "   - 失败时返回nullptr(指针)或抛出异常(引用)" << std::endl;
    
    std::cout << "\n3. const_cast:" << std::endl;
    std::cout << "   - 添加或移除const限定符" << std::endl;
    std::cout << "   - 与C API交互" << std::endl;
    std::cout << "   - 谨慎使用,可能导致未定义行为" << std::endl;
    
    std::cout << "\n4. reinterpret_cast:" << std::endl;
    std::cout << "   - 低级别的位模式重新解释" << std::endl;
    std::cout << "   - 指针和整数之间的转换" << std::endl;
    std::cout << "   - 平台相关,非常危险" << std::endl;
    
    std::cout << "\n5. C风格转换:" << std::endl;
    std::cout << "   - 避免使用,除非与C代码交互" << std::endl;
    std::cout << "   - 可能隐藏错误" << std::endl;
    std::cout << "   - 不够明确" << std::endl;
}

int main()
{
    BestPracticesDemo();
    std::cout << std::endl;
    CastingGuidelines();
    return 0;
}

总结

  1. C++类型转换优势:更安全、更明确、更容易搜索和维护
  2. static_cast
    • 编译时检查的类型转换
    • 基本类型转换、继承层次转换
    • 程序员保证转换的安全性
  3. dynamic_cast
    • 运行时类型检查的安全转换
    • 需要虚函数表(RTTI)
    • 失败时返回nullptr或抛出异常
    • 专门用于多态类层次结构中的向下转换
  4. const_cast
    • 添加或移除const/volatile限定符
    • 与C API交互时使用
    • 修改原本const的对象可能导致未定义行为
  5. reinterpret_cast
    • 低级别的位模式重新解释
    • 指针与整数转换、不相关类型转换
    • 平台相关,使用时需要极其谨慎
  6. 最佳实践
    • 优先使用C++风格转换
    • 根据具体需求选择合适的转换类型
    • 避免不必要的类型转换
    • 使用dynamic_cast进行安全的多态转换
updatedupdated2025-09-202025-09-20