C++语法|C++的类型转换:const_cast、static_cast、reinterpret_cast、dynamic_cast

在C语言中,我们的类型强转都是:
int a = (int)b;

当然在C++中,提供了语言级别的四种类型转换方式:

  • const_cast:去掉常量属性的一个类型转换
  • static_cast:提供编译器认为安全的类型转换
  • reinterpret_cast:类似于C风格的强制类型转换
  • dynamic_cast: 主要用在继承结构中,可以支持RTTI类型识别的上下转换

const_cast

为去掉常量属性的一个类型转换:

const int a = 10;
//int *p = &a; //报错!!

在这里,我们肯定是不能拿普通之战指向一个常量类型的,
我们可以使用C风格的方式进行类型转换,我们也可以用C++风格的类型转换,想把它转成什么类型,尖括号<>就写什么类型

int *p1 = (int*)&a;
int *p2 = const_cast<int*>(&a);

其实这个类型都是语言级别提供的,所以我们无法查看它的源码。
但其实,他们在汇编基本的语法都是一样的:

lea	eax, |a|
mov	dword ptr [p1], eax

lea	eax, |a|
mov	dword ptr [p2], eax

但是在编译阶段,还是有所不同的:

  • const int a 在内存中是占4个字节的
  • 如果是C风格的类型转换,我们可以double *p1 = (double*)&a,double是8个字节的,但是仍然可以编译通过。
  • 如果我们想通过char *p2 = const_cast<char*>(&a), 用不同类型的指针指向一个整型变量,编译会直接报错。

这样可以消除可能的错误,比如说我们的 const int a 只有4个字节有效,但是 double *p1可以访问8个字节的内存


下一个测试:

const int a = 10;
//const_cast 中的类型必须是指针、引用或指向对象类型成员的指针
int b = const)cast<int>(a); //编译错误!

const_cast<这里必须是指针或者引用类型>

总结:
1. 我们的 const_cast<>必须和基础类型保持一致
2. const_cast 中的类型必须是指针或者引用

⭐️static_cast

这是我们用的最多的类型转换。

static_cast几乎能做任何类型的转换,不过他主要是提供编译器认为安全的类型转换。

int main () {
	int a = 10;
	char b = static_cast<int>(a);
}

这种类型转换是被允许的。

但是我们看这个例子:

int *p = nullptr;
short* b = static_cast<short*>(p);

编译器报错提示为:static_cast from 'int *' to 'short *' is not allowed
也就是说,当两个类型之间没有任何联系的时候,这种类型转换会被否决

所以该类型转换其实在大部分情况下都给到了我们编译时的检查。


那么基类和派生类类型能不能用static_cast呢?
当然可以了!因为他们就是有联系的。

retinterpret_cast

这就是C++语言级别提供的和C一样的类型转换风格。

⭐️dynamic_cast

支持RTTI类型识别的上下转换,主要用于继承结构中。

举例

我们先定义三个类,其中Base为抽象基类,Derive1、Derive2分别继承自Base类。
并且我们在类A中有虚函数 virtual void func() = 0;
随后我们提供一个统一接口void showFunc(Base *p)来调用func

class Base {
public:
    virtual void func() = 0;
};
class Derive1 : public Base {
public:
    void fun() { cout << "call Derive1::func" << endl; }
};
class Derive2 : public Base {
public:
    void fun() { cout << "call Derive2::func" << endl; }
};

void showFunc(Base *p) {
    p->func(); // 动态绑定
}

我们做如下调用:

int main () {
    Derive1 d1;
    Derive2 d2;
    showFunc(&d1);
    showFunc(&d2);
    return 0;
}

结果如下:

call Derive1::func
call Derive2::func

那么现在我们突然多了一个需求:
我们需要在Derive2里面写一个新需求:

class Derive2 : public Base {
public:
    void func() { cout << "call Derive2::func" << endl; }
    //Derive2实现新功能的API接口函数
    void derive02func() {
    	cout << "call Derive2::derive02func" << endl;
    }
};

也就是说,现在我们showFunc统一接口,当他动态绑定的是Derive2类的话,我希望它能调用新功能derive02func。我们应如何解决呢?

void showFunc(Base *p) {
    p->func(); // 动态绑定
}

dynamic_cast的使用

此时我们需要关注 *p的类型,当它是Derive2类型的,我们就需要去调用derive02func

  • 第一种就是通过typeid(*p).name == "Derive2"来判断是否为Derive2类型
    但其实我们不会使用这种比较字符串的方式来实现。
  • dynamic_cast !
void showFunc(Base *p) {
	//dynamic_cast会检查p指针是否指向的是一个Derive2类型的毒对象
	Derive2 *pd2 = dynamic_cast<Derive2*>(p);
	if (pd2 != nullptr) {
		pd2->derive02func();
	} else {
		p->func();
	}
}

第一部分的语法为,把Base类型的指针转换成Derive2类型的指针。

这是因为首先p指向的对象里有vfptr虚函数指针,它指向了vftable虚函数表,其中放了RTTI信息。
如果是,dynamic_cast转换类型成功,返回Derive2对象的地址给pd2;
否则,dynamic_cast成功失败,返回nullptr;
所以我们有以下语法:

	if (pd2 != nullptr) {
		pd2->derive02func();
	} else {
		p->func();
	}

由于我们的derive02func()是新写的函数,基类中也不存在该虚函数,所以只能是静态绑定,我们也只能通过Derive2类型的指针来进行访问。
现在再进行调用:

int main () {
	Derive1 d1;
	Derive2 d2;
	showFunc(&d1);
	showFunc(&d2);
}

结果如下:

call Derive1::func
call Derive2::derive02func

总结NOTE:
dynamic_cast往往用在继承结构中,特别是存在虚函数表的情况下,该方法对于统一接口的改进,使得多态能够变得更加灵活。

  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中,四种类型的转换(有时也称为“cast”)用于处理不同数据类型的互相转换,它们各有特定的用途和使用场景。以下是这四种转换的简要说明以及它们在源代码中的基本实现: 1. **static_cast**:这是一种静态类型转换,用于明确且不涉及运行时类型的检查。它可以用于基本类型、指针、引用和内置的enum之间直接的转换。源代码示例: ```cpp int i = 5; double d = static_cast<double>(i); ``` 2. **dynamic_cast**:用于运行时类型检查,主要用于对象之间的类型转换,特别是当基类指针或引用需要转换为派生类类型时。如果类型转换成功,返回指向或引用的对象;否则返回null(对非指针)。例如: ```cpp class Base { ... }; class Derived : public Base { ... }; Base* baseObj = new Derived(); Derived* derivedObj = dynamic_cast<Derived*>(baseObj); ``` 3. **const_cast**:用于修改对象的const属性,即使在常量表达式中也可以用于临时去除const限定。这通常用于函数参数传递或返回值,或者为了修改const成员。注意这是有风险的,因为它打破了const契约: ```cpp const int& constRef = getConstInt(); int& mutableInt = const_cast<int&>(constRef); ``` 4. **reinterpret_cast**:这是最强大但也是最危险的转换,它将一个对象的数据重新解释为另一种类型,无视数据原有的字节布局。通常用于底层内存操作,如指针类型间的转换。不建议用于正常类型转换,仅在必要时使用,例如: ```cpp void* rawMemory = ...; // 假设我们知道它是int数组 int* intPtr = reinterpret_cast<int*>(rawMemory); ``` 请注意,这些类型转换在编译时就会进行,因此源代码中的实现主要体现在编译器层面,而不是直接在源码文件中看到具体的转换操作。实际的转换操作在C++库内部由编译器优化器处理。在代码中,我们主要关注的是转换的语法和意图。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值