c++ 中的类型转换(强制转换和隐式类型转换)
在我们学习c语言的时候,就知道强制类型转换和隐式类型的转换,但是在类型转换的过程中,很有可能一个不注意,容易出问题,这无疑是加大了,程序员的工作量,而且还检查很不好检查。
所以在c++ 中就对类型的转换做了一定的限制,但是实际中大多数人,是在学习了c 语言后才学习 c++ 语言所以就用了 c 语言中的类型转换方式,那么今天我们介绍一下 c++ 中类型转换的方式,他们都是通过类模板的方式实现
const_cast 把const强转成非const修饰
在 c 语言中强转是可以把一个不想关的类型都可以强转,但是这样就很容易出问题,如果我们用了const_cast 如果要把两个两个不相关的类型的const转到非const是不行的。这样就限制了出错的概率,,增强了代码的可读性,但是实际中,大多数还是喜欢采用c语言,但是我们必须得知道。
const int i = 10;//在c++中这样编译器会优化为寄存器变量用volatile
int* j = const_cast<int*>(&i); // const 与非 const 转换
static_cast 隐式类型转换
什么是隐式类型的转换,隐式类型转换,就像c语言中我们可以把一个整型 int 赋值给一个 float 这就是隐式类型的转换。
我们简单的写一个例子
void test()
{
int i = 10;
float j = i; // 在c语言中的隐式类型的转换
// 用static_cast转换
float j = static_cast<float>(i);
}
这样写增强了代码的可读性
reinterpret_cast 不相关类型转换
这强制类型转换是就像 c语言中的强转。
我们举一个例子:
typedef void (* FUNC)();
int DoSomething (int i)
{
cout<<"DoSomething" <<endl;
return 0;
}
void Test ()
{
//
// reinterpret_cast可以编译器以FUNC的定义方式去看待 DoSomething函
数
// C++不保证所有的函数指针都被一样的使用,所以这样用有时会产生不
确定的结果
//
FUNC f = reinterpret_cast< FUNC>(DoSomething );
f();
}
这样我们就把一个函数赋值,还可以调用。
dynamic_cast虚函数中的父类赋给子类的转化
dynamic_cast用于将一个父类对象的指针转换为子类对象的指针或引用(动态
转换)
向上转型:子类对象指针->父类指针/引用(不需要转换)
向下转型:父类对象指针->子类指针/引用(用dynamic_cast转型是安全的)
这里用这种强转必须要虚函数的类,用dynamic_cast来转换父类付给子类的时候,有时候可以,有时候不行,这样用dynamic_cast 强转就会在转变的过程中去判断,如果可以把父类给子类就强转,如果不行就返回0.
class A
{
public :
virtual void f(){}
};
class B : public A
{};
void fun (A* pa)
{
// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
B* pb1 = static_cast<B*>(pa);
B* pb2 = dynamic_cast<B*>(pa);
cout<<"pb1:" <<pb1<< endl;
cout<<"pb2:" <<pb2<< endl;
}
int main ()
{
A a;
B b;
fun(&a);
fun(&b);
return 0;
}
红色标记的是强转失败,因为把父类赋给子类失败。强转就会判断是否成功。
如果用c语言中强转可以成功,但是如果强转后,去访问有可能会访问越界。
explicit关键字
在强转中,对于单参数的构造函数,支持隐式类型的转换,所以当我们不需要隐式类型的转换的时候,我们就可以加上explicit关键字来防止,在构造函数的时候发生隐式类型的转换。
单参数的类构造函数的隐式类型转换。
class A
{
public :
explicit A (int a)
{
cout<<"A(int a)" <<endl;
}
A(const A& a)
{
cout<<"A(const A& a)" <<endl;
}
private :
int _a ;
};
int main ()
{
A a1 (1);
// 隐式转换-> A tmp(1); A a2(tmp);
A a2 = 1; // 这是因为单参数支持隐式类型转换
}
我们加上关键字后,用 = 来进行隐式类型转换,是编译不能通过的。
如果我们不加就可以通过。