C++的四种强制转换

1.static_cast

基本等价于隐式转换的一种类型转换运算符,以前是编译器自动隐式转换,static_cast可使用于需要明确隐式转换的地方。c++中用static_cast用来表示明确的转换。
可以用于低风险的转换:
整型和浮点型

字符与整形

转换运算符

空指针转换为任何目标类型的指针

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

2.const_cast

const_cast的对象类型必须为指针引用或指向对象的指针
用法1:

int main()
{
	const int a = 1;
	int*b = const_cast<int*>(&a);
	*b = 5;
	std::cout << a;
}

断点查看运行到*b = 5;时a的值被设为5了,但最后cout的a的值仍然为1
why?

对于const数据我们更要这样保证:绝对不对const数据进行重新赋值。
如果我们不想修改const变量的值,那我们又为什么要去const呢?

原因是,我们可能调用了一个参数不是const的函数,而我们要传进去的实际参数却是const的,但是我们知道这个函数是不会对参数做修改的。于是我们就需要使用const_cast去除const限定,以便函数能够接受这个实际参数。

用法2:

class father
{
	virtual void func()const
	{
	void* p = this;
	}
	int aa;
};

func()为常成员函数,即通过该函数不可修改类的成员变量
在这里插入图片描述
常成员函数的this指针为const xxx型,即指向的地方的数据不能变,于是使用const_cast:

class father
{public:
	virtual void func()const
	{
		const_cast<father*>(this)->aa = 1;
	}
	int aa;
};

现在可以有针对的修改其中的成员

还有类似的用法:

#include
int main() {
    // 原始数组
    int ary[4] = { 1,2,3,4 };

    // 打印数据
    for (int i = 0; i < 4; i++)
        std::cout << ary[i] << "\t";
    std::cout << std::endl;

    // 常量化数组指针
    const int*c_ptr = ary;
    //c_ptr[1] = 233;   //error

    // 通过const_cast 去常量
    int *ptr = const_cast<int*>(c_ptr);

    // 修改数据
    for (int i = 0; i < 4; i++)
        ptr[i] += 1;    //pass

    // 打印修改后的数据
    for (int i = 0; i < 4; i++)
        std::cout << ary[i] << "\t";
    std::cout << std::endl;

    return 0;
}

/*  out print
    1   2   3   4
    2   3   4   5
*/

小结:
1、常量指针被转化成非常量的指针,并且仍然指向原来的对象;
2、常量引用被转换成非常量的引用,并且仍然指向原来的对象;
3、const_cast一般用于修改指针。如const char *p形式。
4、const_cast不能修改const数据本身的值,但是可以去掉const指针的const属性来改变其指向的值

3.dynamic_cast

定义两个简单的类:

class father
{
};
class son:public father
{
public:
	int num;
};

将父类指针转换为子类指针:

int main()
{
	father f1;
	son s1;
	father* pfather=&f1;
	son* pson = &s1;
	son* pson = pfather;
}

C++的四种强制转换_第1张图片
此时pson虽然为子类指针,但他实际指向的是父类对象的空间,编译器认为可能通过该指针访问到此空间中不存在的部分,因此编译不能通过。

因此使用dynamic_cast(动态转换)通过RTTI(运行时类型识别)来做转换,而RTTI通过虚函数来实现,因此在父类里添加一个虚函数:

class father
{
	virtual void func() {};
};

此时再做转换,即使访问了不存在的对象在编译阶段将不会出错:

int main()
{
	father f1;
	son s1;
	father* pfather=&f1;
	son* pson = &s1;
    pson = dynamic_cast<son*>(pfather);
    pson->num = 1;
}

而是在运行阶段时报错,并将pson置为空:
C++的四种强制转换_第2张图片
于是可以这样修改主函数:

int main()
{
	father f1;
	son s1;
	father* pfather=&f1;
	son* pson = &s1;
    pson = dynamic_cast<son*>(pfather);
	if(pson!=nullptr)
	pson->num = 1;
}

若pson在程序运行时指向的为子类空间,则可以修改num,若指向的为父类空间,则也不会报错,更加灵活。

4.reinterpret_cast重新诠释

执行各种高风险转换,如整型转指针,各种类型的指针转换,父类子类指针的转换

int i=1;
int*a=reinterpret_cast(int*)i;

等价于c中的强制转换:

int i=1;
int*a=(int*)i;

static_cast虽然也不是一种绝对安全的转换,但是它在转换时,还是会进行必要的检测(诸如指针越界计算,类型检查)。reinterpret_cast完全是肆无忌惮,直接从二进制开始重新映射解释,是极度不安全的,再次提醒,不到万不得已,不要使用。

你可能感兴趣的:(C++进阶,c++)