C++高级使用技巧:强制类型转换

        在C语言中,如果表达式赋值运算符左右两侧变量或表达式的数据类型不同,或者形参变量与实参变量类型不匹配,或者返回值变量类型与接收值类型不一致时,就需要进行类型转化,C++语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。

        隐式类型转化是编译器在编译阶段自动进行,能转就转,不能转就会发生编译失败;而显式类型转化(强转)是用户自己进行类型转换操作。

        只有相近类型之间才能发生隐式类型转换,比如int、char、double、unsigned int表示的都是数据的大小,只不过它们表示的范围和精度不同,它们之间可以发生隐式类型转换,而指针类型表示的是地址编号,因此整型和指针类型之间不能发生隐式类型转换,若需要转换只能显示类型转换。

        标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:static_cast、const_cast、dynamic_cast、reinterpret_cast。

1.static_cast

        static_cast相当于传统的C语言里的强制转换,该运算符把expression转换为new_type类型,用来强迫隐式转换,将隐式转换显式化表示出来。注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性

        可以用于低风险的转换:整型与浮点型、字符与整形、转换运算符、空指针转换为任何目标类型的指针;

        不可以用与风险较高的转换:不同类型的指针之间互相转换、整型和指针之间的互相转换、不同类型的引用之间的转换


#include <iostream>
#include <string>

class CInt {
public:
	//对int的转换运算符
	operator int() {
		return m_nInt;
	}

	int m_nInt;
};

int main() {
	int n = 5;
	float f = 10.0f;
	double dbl = 1.0;
	
	//本质上发生了隐式转换,将int类型的5转换为float类型
	//但是代码上写的不够明确
	f = n;

	//static_cast作用等价于隐式转换,但是更加明确
	f = static_cast<float>(n);

	//低风险的转换
	//整型与浮点型
	n = static_cast<int>(dbl);

	//字符与整型
	char ch = 'a';//占用一个字节
	n = static_cast<int>(ch);

	//void*指针的转换
	void* p = nullptr;
	int* pN = static_cast<int*>(p);

	//转换运算符的方式
	CInt nObj;
	//若没有前面的,这里会把nObj当做对象无法转换
	//等价于int kk=nObj
	int k = static_cast<int>(nObj);

	//高风险的转换
	int kk;
	char* p;
	//整型与指针类型的转换
	p = kk;//不可以转换
	char* k = static_cast<char*>(kk);//不可以转换

	//不同指针类型的转换
	int* pK;
	char* k = pK;//不可以转换
	char* k = static_cast<char*>(pK);//不可以转换

	return 0;
}
#include <iostream>
#include <string>

//基类与派生类之间的转换

class CFather
{
public:
	CFather() {
		m_nTest = 3;
	}

	virtual void foo() {
		std::cout << "CFather()::void foo()" << std::endl;
	}

	int m_nTest;
};

class CSon : public CFather
{
	virtual void foo() {
		std::cout << "CSon::void foo()" << std::endl;
	}
};

int main() {
	CFather* pFather = nullptr;
	CSon* pSon = nullptr;

	//父类转子类,不安全,子类可能包含的内容更多
	pSon = pFather;//无法通过
	pSon = static_cast<CSon*>(pFather);//可以通过,但是不安全,没有运行时的检测

	//子类转父类,安全,子类包含的内容要大于父类
	pFather = pSon;//可以通过
	pFather = static_cast<CFather*>(pSon);//可以通过
}

2.const_cast

        删除变量的const属性,方便赋值,转换后就可以对const变量的值进行修改,如下:

int main()
{

    const int a1 = 2;
	int* p1 = const_cast<int*>(&a1);//取消变量a的const属性
	*p1 = 3;
	cout << a1 << endl; //2
	cout << *p1 << endl;//3

    //volatile强制每次访问变量a都去内存中去读取,防止编译器的优化
	volatile const int a2 = 2;
	int* p2 = const_cast<int*>(&a2);//取消变量a的const属性
	*p2 = 3;
	cout << a2 << endl; //3
	cout << *p2 << endl;//3
	return 0;
}

3.dynamic_cast

        用于在运行时进行安全的向下转型(downcasting)和跨继承层次的转型。在面向对象的程序设计中,经常会存在基类指针或引用指向派生类对象的情况。当需要将基类指针或引用转换为派生类指针或引用时,可以使用 dynamic_cast运算符来进行类型转换

        1. 向下转型(Downcasting):将基类指针或引用转换为派生类指针或引用。如果转型是合法的,即基类指针或引用实际指向的是派生类对象,那么转型成功并返回派生类指针或引用。如果转型不合法,即基类指针或引用实际指向的不是派生类对象,那么转型失败,返回 nullptr(对于指针)或抛出 std::bad_cast 异常(对于引用)。

        2. 跨继承层次转型:在多重继承中,可以使用 dynamic_cast 跨越继承层次进行类型转换。这样可以在继承层次中的不同分支间进行安全的类型转换。

#include <iostream>

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

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

int main() {
    
    Base* basePtr = new Derived;

    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
    if (derivedPtr) {
        derivedPtr->someFunction();
    } else {
        std::cout << "Dynamic cast failed" << std::endl;
    }

    delete basePtr;
    return 0;
}

4.reinterpret_cast

        C++还提供了reinterpret_cast用于任意类型的转换,即reinterpret_cast运算符允许将任意指针转换到其他指针类型,也允许做任意整数类型和任意指针类型之间的转换。转换时,执行的是逐个比特复制的操作。reinterpret中文意为“重新解释”。从本质上说这种转换是不安全的、依赖于实现的,这种安全性只能由程序员自己来保证。

reinterpret_cast 的一个实际用途是在哈希函数中,即,通过让两个不同的值几乎不以相同
的索引结尾的方式将值映射到索引。
#include <iostream>
using namespace std;

// Returns a hash code based on an address
unsigned short Hash( void *p ) {
   unsigned int val = reinterpret_cast<unsigned int>( p );
   return ( unsigned short )( val ^ (val >> 16));
}

using namespace std;
int main() {
   int a[20];
   for ( int i = 0; i < 20; i++ )
      cout << Hash( a + i ) << endl;
}

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

弘毅—至善

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值