七、类型转换操作符和自定义类型转换
A a;
B b (a);
B b = a;
B b = static_cast<B> (a);
1. 可以通过为目标类型提供具有类型转换功能的构造函数完成自定义类型转换,也可以通过为源类型提供类型转换操作符达到同样的目的。
2. 通过使用explicit关键字可以强制通过构造函数完成的类型转换必须显式完成。
3. 类型转换操作符函数
operator 目标类型 (void) {...}
当隐式类型转换与类型转换运算符同时存在时,优先选择类型转换运算符;
实例:
/*类型转换*/
#include <iostream>
using namespace std;
class Point3D;
class Point2D{
public:
Point2D(int x,int y):m_x(x),m_y(y){}
operator Point3D(void);
private:
int m_x;
int m_y;
friend class Point3D;
};
class Point3D{
public:
// 构造函数
Point3D(int x,int y,int z):m_x(x),m_y(y),m_z(z){} // 使用 Point3D pt3(pt2); 结果 (10,100,400)
Point3D(const Point2D&pt):m_x(pt.m_x),m_y(pt.m_y),m_z(0){} // 使用 Point3D pt3 = pt2; 结果 (10,100,0)
void Print(void){
cout<<"("<<m_x<<","<<m_y<<","<<m_z<<")"<<endl;
}
private:
int m_x;
int m_y;
int m_z;
};
Point2D::operator Point3D(void){
return Point3D(m_x,m_y,400);
}
int main(void)
{
Point2D pt2(10,100);
Point3D pt3(30,20,10);
pt3 = pt2; // 隐式类型转换
pt3.Print();
return 0;
}
结果: (10,100,400)
2. 通过使用explicit关键字可以强制通过构造函数完成的类型转换必须显式完成。
/*类型转换*/
#include <iostream>
using namespace std;
class Point3D;
class Point2D{
public:
Point2D(int x,int y):m_x(x),m_y(y){}
operator Point3D(void);
private:
int m_x;
int m_y;
friend class Point3D;
};
class Point3D{
public:
// 构造函数
Point3D(int x,int y,int z):m_x(x),m_y(y),m_z(z){}
explicit Point3D(const Point2D&pt):m_x(pt.m_x),m_y(pt.m_y),m_z(0){}
void Print(void){
cout<<"("<<m_x<<","<<m_y<<","<<m_z<<")"<<endl;
}
private:
int m_x;
int m_y;
int m_z;
};
Point2D::operator Point3D(void){
return Point3D(m_x,m_y,400);
}
int main(void)
{
Point2D pt2(10,100);
Point3D pt3(30,20,10);
// pt3 = pt2;
pt3 = static_cast<Point3D>(pt2); // 显示类型转换
pt3.Print();
return 0;
}
结果:(10,100,0)
五种显示类型的转换
A.通用类型转换: 目标类型(标识符)
eg: char c = 'a';
int n = char(c);
c = int(n);
B.静态类型转换: static_cast<目标类型>(标识符)
eg: char c = 'a';
int n = static_cast<int>(c);
c = static_cast<char>(n);
备注:在目标类型和源类型之间只要有一个方向上可以做隐式类型转换,那 么在两个方向上就都可以做静态类型转换;
主要用于基本类型之间和具有继承关系的类型之间的转换。
这种转换一般会更改变量的内部表示方式,因此,static_cast应用于指针类型转换没有太大意义。
//基本类型转换
int i=0;
double d = static_cast<double>(i); //相当于 double d = (double)i;
//转换继承类的对象为基类对象
class Base{};
class Derived : public Base{};
Derived d;
Base b = static_cast<Base>(d); //相当于 Base b = (Base)d;
C.动态类型转换: dynamic_cast<目标类型>(标识符)
它与static_cast相对,是动态转换。这种转换是在运行时进行转换分析的,并非在编译时进行。
只能在继承类对象的指针之间或引用之间进行类型转换。进行转换时,会根据当前运行时类型信息,判断类型对象之间的转换是否合法。dynamic_cast的指针转换失败,可通过是否为null检测,引用转换失败则抛出一个bad_cast异常。
例:
class Base{};
class Derived : public Base{};
//派生类指针转换为基类指针
Derived *pd = new Derived;
Base *pb = dynamic_cast<Base*>(pd);
if (!pb)
cout << "类型转换失败" << endl;
//没有继承关系,但被转换类有虚函数
class A{
virtual ~A(); //有虚函数
};
class B{}:
A* pa = new A;
B* pb = dynamic_cast<B*>(pa);
如果对无继承关系或者没有虚函数的对象指针进行转换、基本类型指针转换以及基类指针转换为派生类指针,都不能通过编译。
D.常量类型转换: const_cast<目标类型>(标识符)
eg: int*p;
const int* pc = const_cast<int*>(p);
p = const_cast<int*>(pc);
备注:试图通过常量类型转换修改常量的值可能导致不可预知的后果; 必须是同类型之间相互转换
一、用于去除指针变量的常量属性,将它转换为一个对应指针类型的普通变量。反过来,也可以将一个非常量的指针变量转换为一个常指针变量。
这种转换是在编译期间做出的类型更改。
int a = 10;
const int* pci = &a;
int* pk = const_cast<int*>(pci); //相当于int* pk = (int*)pci;
//*pci = 100;此时是会出现编译错误的(assignment of read-only location),因为pci被定义为指向常量的指针,因//此不能通过它来修改指向变量的值
*pk = 100; //此时是正确的,即a的值被修改为100。即便前面a的定义被修改//为const int a = 10,a同样被修改。
cout<<a<<","<<*pni<<","<<endl; // 100,100 修改成功
const A* pca = new A;
A* pa = const_cast<A*>(pca); //相当于A* pa = (A*)pca;
二、出于安全性考虑,const_cast无法将非指针的常量转换为普通变量。即括号中的变量只能是指针变量,且< >中的写的必须是某种类型变量的指针,即int *, double *等等。
像下面的代码是错误的。 (错误:在类型 ‘int’ 上使用 const_cast 无效,因为它既不是指针,也不是引用,也不是数据成员指针)
const int b = 200;
int d = const_cast<int>(b);
E.重解类型转换: reinterpret_cast<目标类型>(标识符)
说明:
reinterpret_cast<指针int */引用int &/void */其他变量类型int>
一、 将一个类型的指针转换为另一个类型的指针。这种转换不用修改指针变量值存放格式(不改变指针变量值),只需在编译时重新解释指针的类型就可做到.
1>基本类型指针的类型转换
eg: void* pv = ...;
int* pn = reinterpret_cast<int*>(pv);
pv = reinterpret_cast<void*>(pn);
eg:
double d=9.2;
double* pd = &d;
int *pi = reinterpret_cast<int*>(pd); //相当于int *pi = (int*)pd;
2>不相关的类的指针的类型转换
class A{};
class B{};
A* pa = new A;
B* pb = reinterpret_cast<B*>(pa); //相当于B* pb = (B*)pa;
二、reinterpret_cast 可以将指针值转换为一个整型数,但不能用于非指针类型的转换。
//指针转换为整数
long l = reinterpret_cast<long>(pi); //相当于long l = (long)pi;
三、但是reinterpret_cast只能用于指针转换,即最后的括号中的变量只能是指针才行。像下面的代码在编译时将通不过。
double f2 = 12.36;
int of = reinterpret_cast<int>(f2);//因为f2不是指针,而是double类型的普通变量。
八、函数操作符
以平方为例:
/*函数操作符*/
#include <iostream>
using namespace std;
class Square{
public:
int operator()(int n)const{
return n*n;
}
};
int main(void)
{
Square sq;
cout<<sq(2)<<endl;
return 0;
}