又称为“标准转换”,包括以下几种情况:
(1)算术转换(Arithmetic conversion): 在混合类型的算术表达式中,最宽的数据类型成为目标转换类型。
int iVal = 3;
double dval = 3.14159;
ival+dval; //ival被提升为double类型
(2)一种类型的表达式赋值给另一种类型的对象:目标类型是被赋值对象的类型
int *pi = 0; // 0被转化为int *类型
ival = dval; // double -> int
(3)将一个表达式作为实参传递给函数调用,此时形参和实参类型不一致:目标转换类型为形参的类型
double sqrt(double);
cout<<"The square root of 2 is"<
(4)从一个函数返回一个表达式,表达式类型与返回类型不一致:目标类型转化为函数的返回类型
double difference(int ival1,int ival2)
{
return ival1-ival2;
//返回值被提升为double类型
}
又被称为“强制类型转换”(cast)
C 风格: (type-id)
C++风格:static_cast、dynamic_cast、reinterpret_cast和const_cast.
用法:static_cast
说明:该运算符把expression转化为type-id类型,但没有运行时类型检查来保证转换的安全性。
为什么需要static_cast强制转换?
情况1:void指针 -> 其他类型指针
情况2:改变通常的标准转换
情况3:避免出现可能多种转换的歧义
它主要有如下几种用法:
(1) 用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换是安全的(把子类的指针或引用转换为基类表示);进行下行转换(把基类指针或引用转换为子类的),由于没有动态类型检查,所以是不安全的。
(2)用于基本数据类型之间的转换,如把int转换为char,这种转化的安全性要由开发人员来保证。
(3)把void类型转换为目标类型的指针(不安全)
(4)把任何类型转化为void类型
注意:static_cast不能转换掉expression的const、volitale或__unaligned属性。
用法:danamic_cast
说明:该运算符把expression转换为type-id的对象。type-id必须是类的指针、类的引用或者void*;如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。
为什么要用dynamic_cast强制转换?
简单的说,当无法使用virtual函数的时候
典型案例:
W公司提供给我们一个类库,其中提供一个类Employee 以头文件Employee.h 和类库 .lib分发给用户,显然我们无法得到类的实现的源代码。
//Employee.h
class Employee
{
public:
virtual int salary();
};
class Manager: public Employee
{
public:
int salary();
};
class Programmer: public Employee
{
public:
int salary();
}
公司在开发的时候建立有如下类:
class MyCompany
{
public:
void payroll(Employee *pe);
// ...
};
void MyCompany::payroll(Employee *pe)
{
//do something
}
但是开发到后期,我们希望能增加一个bonus()的成员函数到W公司提供的类库中。
假设我们知道源代码的情况下,很简单,增加虚函数:
//Employee.h
class Employee
{
public:
virtual int salary();
virtual int bonus();
};
class Manager: public Employee
{
public:
int salary();
};
class Programmer:public Employee
{
public:
int salary();
int bonus();
};
//Employee.cpp
...
int Programmer::bonus()
{
//...
}
//payroll 通过多态来调用bonus()
class MyCompany
{
public:
void payroll(Employee *pe);
//...
};
void MyCompany::payroll(Employee *pe)
{
//do something
// pe->bonus();
}
但是现在的情况是,我们并不能修改源代码,怎么办?dynamic_cast华丽登场了!
在Employee.h 中增加bonus()声明,在另一个地方定义此函数,修改调用函数payroll() . 重新编译,OK!
//Employee.h
class Employee
{
public:
virtual int salary();
};
class Manager: public Employee
{
public:
int salary();
};
class Prigrammer: public Employee
{
public:
int salary();
int bonus(); //直接在这里扩展
};
//somewhere.cpp
int Programmer::bonus()
{
//define ...
}
class MyCompany
{
public:
void payroll(Employee *pe);
//
};
void MyCompany::payroll(Employee *pe)
{
Programmer *pm = dynamic_cast(pe);
//如果pe实际指向一个Programmer对象,danamic_cast成功,并且开始指向Programmer对象起始处
if(pm)
{
//call Programmer::bonus()
}
// 如果pe不是实际指向Programmer对象,dynamic_cast失败,并且pm = 0
else
{
//use Employee member functions
}
}
dynamic_cast主要用于类层次之间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间进行上下转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
class Base
{
public:
int m_iNum;
virtual void foo();
};
class Derived:public Base
{
public:
char *m_szName[100];
};
void func(Base *pb)
{
Derived *pd1 = static_cast(pb);
Derived *pd2 = dynamic_cast (pb);
}
在上面的代码段中,如果pb实际指向一个Derived类型的对象,pd1和pd2是一样的,并且对这两个指针执行Derived类型的任何操作都是安全的;如果pd实际指向一个Base类型的对象,那么pd1将是一个指向该对象的指针,对它进行Derived类型的操作将是不安全的,而pd2将是一个空指针(因为dynamic_cast失败)
另外要注意:Base要有虚函数,否则会编译出错;static_cast则没有这个限制。这是由于运行时类型检查需要运行时类型信息,而这个信息是存储在类的虚函数表中,只有定义了虚函数的类才有虚函数,没有定义虚函数的类是没有虚函数表的。