相信熟悉C语言与C++的人都有这样的感觉C++的语法检测比C语言要严格的多,下面是C++在
类型转换时做出的改进,有四个关键词,下面我会和大家一起来研究它们的用法,讲解我会通过注释的方法展现。
//首先我们来看c 中的类型转换
int i=10;//相似类型可以发生隐式转换
double d=i;
int *p=&i;//非相似类型,不可以发生隐式类型转换,需要改成如下
int j=p;
int *p=&i;//强制类型的转换
int j=(int)p;
const int *p1=p;//const 与 非const之间的转换
int* p2=(int*)p1;
//下面我们来看看C++之中的类型转换
//把隐式类型转化的情况通过四个关于类型转换的关键字来规范,防止发生数据的丢失
//关键字1:static_cast用于非状态类型的转换(静态转换),不可用在不相似类型的转换
//相当于c语言中的.隐式类型转换
int i=10;
double d=static_cast<double>(i);
//关键字2;reinterpret_cast用于非相似类型之间的转换,(有时会做出很bug的事)
int *p=&i;
int j=reinterpret_cast<int>(p);
//关键字3:const_cast去const 属性
const int* p1=p;
int *p2=const_cast<int *>(p1);
注:void Test()
{
const int a=10;
cout<<a<<endl;
int* p=const_cast<int*>(&a);
*p=20;
cout<<*p<<endl;
cout<<a<<endl;
}
//大家运行以后可以发现输出的是10,20,10,而我们想的是10,20,20.为什么呢?
//这是一种编译器的优化可以把上段程序改成如下
//加入volatile防止编译器的优化,这时的输出就是10,20,20了
void Test()
{
volatile const int a=10;
cout<<a<<endl;
int* p=const_cast<int*>(&a);
*p=20;
cout<<*p<<endl;
cout<<a<<endl;
}
//关键词4c++引入
//dynamic_cast用于将父类对象的指针或引用转换为子类对象的指针或引用(动态转换),为什么要这样做呢
//我们可以通过这种方法知道指针到底是指向父类的,还是指向子类的。
//注:向上转换:子类对象指针-》父类指针/引用(不需要转换)
//向下转型:父类对象指针-》子类对象指针/引用(用dynamic_cast转型是安全的)
//1,dynamic_cast只能用于含有虚函数的类。
//2.dynamic_cast 会先检查是否能转换成功,能转换成功则转换,不能则返回0
class A
{
public:
Virtual void f()
{
cout<<“A::f”<<endl;
}
int _a;
};
class B:public A
{
public:
Virtual void f()
{
cout<<“B::f”<<endl;
}
int _b;
};
Void func (A* p)
{
p->f();
}
void Test()
{
A a;
B b;
func(&a);
func(&b);
}
//这时的输出结果是
A::f
B::f
//下面我们修改下代码
class A
{
public:
Virtual void f()
{
cout<<“A::f”<<endl;
}
int _a;
};
class B:public A
{
public:
virtual void f()
{
cout<<“B::f”<<endl;
}
int _b;
};
Void func (A* p)
{
p->f();
B* p1=(B*)p;
B* p2=dynamic_cast<B*>(p);
printf (“%p,%p\n”,p1,p2)
}
void Test()
{
A a;
B b;
func(&a);
func(&b);
}
//这时输出的是
A::f
001CFCE0 00000000//可以看到第一种转化转化出来了,第二个没有返回0,第二个会更安全
//dynamic_cast 会先检查是否能转换成功,能转换成功则转换,不能则返回0
B::f
003EF980,003EF980 //如果本身是子类向子类就是没有问题的
最好要附加一个关键字
如下代码构成的场景
class AA
{
public:
AA(int a)
:_a(a)
{}
protected:
int _a;
}
void FAA(AA a)
{
}
int main()
{
AA a1(10);
AA a2=20;//发生了隐式类型的转换---具有单参数构造函数的类型
//先用20 构造了一个AA类型的对象,在用这个对象拷贝构造a2;因为这个临时对象是具有常属性的可以这样验证
//const AA& a2=20;没有报错说明确实产生了具有常属性的中间变量
//但其实大多数编译器都会有优化
FAA(a1);
FAA(30);
}
下面我们来修改一下程序
class AA
{
public:
AA(int a)
:_a(a)
{
cout<<“构造”<<endl;
}
AA(const AA& a)
{
cout<<“拷贝构造”<<endl;
}
protected:
int _a;
}
void FAA(AA a)
{
}
int main()
{
AA a1(10);
AA a2=20;
FAA(a1);
FAA(30);
}
//运行的结果是
// 构造
// 构造
// 拷贝构造
// 构造
//运行一下我们可以看到 AA a2=20;时 并没有发生一次拷贝构造,一次构造
//仅仅发生了一次构造。所以说是经过了优化
//但是官方没有规定是否一定要优化,所以不优化也没错
//下面我们来加上关键字看会发生什么
class AA
{
public:
explicit AA(int a)//不想让优化发生(不想发生隐式类型的转换),加上关键字explicit
:_a(a)
{
cout<<“构造”<<endl;
}
AA(const AA& a)
{
cout<<“拷贝构造”<<endl;
}
protected:
int _a;
}
void FAA(AA a)
{
}
int main()
{
AA a1(10);
AA a2=20;
FAA(a1);
FAA(30);
}
//这时就会报错,无法从int 转化为 AA。