• C++ - 类型转换


    C/C++知识点

    C++类型转换

    旧式转型 C 风格的强制类型:

    TYPE b = (TYPE) a

    例如:

    int i = 48;	
    char c = (char) i;
    
    • 1
    • 2

    新式转型 C++ 风格的类型转换提供了 4 种类型转换操作符来应对不同场合的应用。

    TYPE b = 类型操作符 ( a )

    类型操作符 = static_cast | reinterpreter_cast | dynamic_cast | const_cast

    static_cast

    静态类型转换(斯文的劝导,温柔的转换),类似于 C 语言中的隐式转换,如 int 转换成 char 。

    主要用法:

    • 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。上行指针或引用(派生类到基类)转换安全,下行(基类到派生类)转换不安全。

    • 用于基本数据类型之间的转换,如把 int 转换成 char ,把 int 转换成 enum 。这种转换的安全性也要开发人员来保证。

    • 把空指针转换成目标类型的空指针。

    • 把任何类型的表达式转换成 void 类型。

    #include 
    
    using namespace std;
    
    class Animal {
    public:
    	virtual void cry() = 0;
    };
    
    class Cat :public Animal
    {
    public:
    	void cry()
    	{
    		cout << "喵喵瞄" << endl;
    	}
    };
    
    class Dog :public Animal
    {
    public:
    	void cry()
    	{
    		cout << "汪汪汪" << endl;
    	}
    };
    
    • 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

    用法一:父子类之间的类型转换

    Dog* dog1 = new Dog();
    Animal* a1 = static_cast<Animal*>(dog1); //子类的指针转型到父类指针
    
    Dog* dog1_1 = static_cast<Dog*>(a1);     //父类的指针转型到子类的指针
    //父子到子类,有风险,虽然下面这句不会报错,但是狗类转换成猫类是完全错误的做法
    Cat* cat1 = static_cast<Cat*>(a1);
    
    Dog dog2;
    Animal& a2 = static_cast<Animal&>(dog2); //子类的引用转型到父类的引用
    Dog& dog2_2 = static_cast<Dog&>(a2);     //父类到子类引用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    用法二:基本类型的转换

    int  kk = 234;
    char cc = static_cast<char>(kk);
    
    • 1
    • 2

    用法三:把空指针转换成目标类型的空指针

    int* p = static_cast<int*>(NULL);
    Dog* dp = static_cast<Dog*>(NULL);
    
    • 1
    • 2

    用法四:把任何类型的表达式转换成 void 类型

    int* pi = new int[10];
    void* vp = static_cast<void*>(pi);
    
    • 1
    • 2

    reinterpret_cast

    重新解释类型(挂羊头,卖狗肉))不同类型间的互转,数值与指针间的互转。

    用法: TYPE b = reinterpret_cast ( a )

    TYPE 必须是一个指针、引用、算术类型、函数指针

    忠告: 滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。

    #include 
    
    using namespace std;
    
    class Animal {
    public:
    	void cry() {
    		cout << "动物叫" << endl;
    	}
    };
    
    class Cat :public Animal
    {
    public:
    	void cry()
    	{
    		cout << "喵喵瞄" << endl;
    	}
    
    };
    
    class Dog :public Animal
    {
    public:
    	void cry()
    	{
    		cout << "汪汪汪" << endl;
    	}
    
    };
    
    • 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

    用法一:数值与指针之间的转换

    int* p = reinterpret_cast<int*>(0x99999);
    int val = reinterpret_cast<int>(p);
    
    • 1
    • 2

    用法二:不同类型指针和引用之间的转换

    Dog  dog1;
    Animal* a1 = &dog1;
    a1->cry();	//动物叫
    
    Dog* dog1_p = reinterpret_cast<Dog*>(a1);
    Dog* dog2_p = static_cast<Dog*>(a1);   //如果能用static_cast ,static_cast 优先
    dog1_p->cry();	//汪汪汪
    dog2_p->cry();	//汪汪汪
    
    //Cat* cat1_p = static_cast(a1);	//输出喵喵喵
    //Cat* cat2_p = static_cast(dog1_p); //报错,不同类型指针转换不能使用static_cast
    Cat* cat2_p = reinterpret_cast<Cat*>(dog1_p);	//但是这个强制转换不会报错
    cat2_p->cry();	//喵喵喵
    
    Animal& a2 = dog1;
    Dog& dog3 = reinterpret_cast<Dog&>(a2);//引用强转用法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    dynamic_cast

    动态类型转换

    • 将一个基类对象指针 cast 到继承类指针,dynamic_cast 会根据基类指针是否真正指向继承类指针来做相应处理。失败返回 null ,成功返回正常 cast 后的对象指针。

    • 将一个基类对象引用 cast 继承类对象,dynamic_cast 会根据基类对象是否真正属于继承类来做相应处理。失败抛出异常 bad_cast 。

    注意: dynamic_cast 在将父类 cast 到子类时,父类必须要有虚函数一起玩。

    #include 
    
    using namespace std;
    
    class Animal {
    public:
    	virtual void cry() = 0;
    };
    
    class Cat :public Animal
    {
    public:
    	void cry()
    	{
    		cout << "喵喵瞄" << endl;
    	}
    
    	void play()
    	{
    		cout << "爬爬树"<<endl;
    	}
    };
    
    class Dog :public Animal
    {
    public:
    	void cry()
    	{
    		cout << "汪汪汪" << endl;
    	}
    
    	void play()
    	{
    		cout << "溜达溜达" << endl;
    	}
    };
    
    • 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

    用法一:指针类型转换

    void animalPlay(Animal* animal) {
    	animal->cry();
    
    	Dog* pDog = dynamic_cast<Dog*>(animal);
    	if (pDog) {
    		pDog->play();
    	}
    	else { //pDog == NULL
    		cout << "不是狗,别骗我!" << endl;
    	}
    
    	Cat* pCat = dynamic_cast<Cat*>(animal);
    	if (pCat) {
    		pCat->play();
    	}
    	else { //pDog == NULL
    		cout << "不是猫,别骗我!" << endl;
    	}
    }
    
    int main() {
    	Dog* dog1 = new Dog();
    	Animal* a1 = dog1;
    	animalPlay(a1);
    
    	cout << endl;
    
    	Cat* cat1 = new Cat();
    	Animal* a2 = cat1;
    	animalPlay(a2);
        
    	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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SLQT3wtb-1659797530057)(C++常见知识点及问题.assets/image-20220801103058966.png)]

    用法二:引用类型转换

    void animalPlay(Animal& animal) {
    	animal.cry();
    
    	try {
    		Dog& pDog = dynamic_cast<Dog&>(animal);
    		pDog.play();
    	}
    	catch (std::bad_cast bc) {
    		cout << "不是狗,那应该是猫" << endl;
    	}
    
    	try {
    		Cat& pCat = dynamic_cast<Cat&>(animal);
    		pCat.play();
    	}
    	catch (std::bad_cast bc) {
    		cout << "不是猫,那应该是上面的狗" << endl;
    	}
    }
    
    int main() {
    	Dog* dog1 = new Dog();
    	Dog dog2;
    	animalPlay(dog2);
    
    	cout << endl;
    
    	Cat* cat1 = new Cat();
    	Cat cat2;
    	animalPlay(cat2);
    
    	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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HZPIDveE-1659797530059)(C++常见知识点及问题.assets/image-20220801103246366.png)]

    const_cast

    去掉 const 属性。(仅针对于指针和引用)

    #include 
    
    using namespace std;
    
    void demo(const char* p)
    {
    	//对指针去掉cost 重新赋值
    	char* p1 = const_cast<char *>(p);
    	p1[0] = 'A';
    
    	//直接去掉const修改
    	const_cast<char*>(p)[1] = 'B';
    	
    	cout << p << endl;
    
    }
    
    void demo(const int p)
    {
    	int q = p;
    	//const_cast(p) = 888;//报错,不能对非指针和引用进行const 转换
    	cout << p << endl;
    }
    
    int main(void)
    {
    	//字符串数组
    	//char p[] = "12345678";
    	//demo(p);  //合情合理
    
    	//常量字符串不能去掉const 修改
    	//警告: 在去掉常量限定符之前,保证指针所指向的内存能够修改,不能修改则会引起异常。
    	const char* cp = "987654321";
    	demo(cp);
    
    	system("pause");
    	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

    类型转换使用建议

    1)static_cast 静态类型转换,编译的时 c++ 编译器会做编译时的类型检查(隐式转换)。基本类型转换,父子类之间合理转换。

    2)若不同类型之间,进行强制类型转换,用 reinterpret_cast<>() 进行重新解释。

    注意: C 语言中能隐式类型转换的,在 c++ 中可用 static_cast<>() 进行类型转换,因 c++ 编译器在编译检查一般都能通过;C 语言中不能隐式类型转换的,在 c++ 中可以用 reinterpret_cast<>() 进行强制类型解释

    总结: static_cast<>() 和 reinterpret_cast<>() 基本上把C语言中的强制类型转换给覆盖,注意 reinterpret_cast<>() 很难保证移植性。

    3)dynamic_cast<>() ,动态类型转换,安全的虚基类和子类之间转换,运行时类型检查。

    4)const_cast<>() ,去除变量的只读属性。

    最后的忠告: 程序员必须清楚的知道 —— 要转的变量,类型转换前是什么类型,类型转换后是什么类型,转换后有什么后果。

    C ++大牛建议: 一般情况下,不建议进行类型转换,避免进行类型转换。

  • 相关阅读:
    LeetCode 第12题:整数转罗马数字(Python3解法)
    基于SpringMVC+Hibernate开发学生成绩管理系统
    SpringBoot集成flink
    领域驱动模型设计与微服务架构落地-从项目去剖析领域驱动
    《搞定音频技术》
    android学习day1
    java算法题 Day86
    扬帆际海:shopee本土店的知识分享
    mybatis -- 打印完整sql(带参数)
    C数据结构-堆的实现思路和堆排序的实现
  • 原文地址:https://blog.csdn.net/Newin2020/article/details/126202649