1. 关键字explicit
通过关键字explicit的作用,我们可以禁止“单参数构造函数”被用于自动类别转换。
在 C++ 中, 如果一个类有只有一个参数的构造函数,C++ 允许一种特殊的声明类变量的方式。在这种情况下,可以直接将一个对应于构造函数参数类型的数据直接赋值给类变量,编译器在编译时会自动进行类型转换,将对应于构造函数参数类型的数据转换为类的对象。如果在构造函数前加上 explicit 修饰词, 则会禁止这种自动转换,在这种情况下,即使将对应于构造函数参数类型的数据直接赋值给类变量,编译器也会报错。
例如:
class String
{
String(cost char * p);
};
String s1= “hello”; //ok 隐式转换,等价于String s1=String(“hello”);
但是有的时候可能不需要这种隐式转换:
class String
{
String(int n); //本意是预先分配n个字节给字符串
String(constchar * p);
};
下面正常写法:
String s2(10);
String s3=String(10);
//都分配10个字节的空字符串
但下面的写法就有问题了:
String s4=10; //编译通过,也分配10个字节的空字符串
String s5= ‘a’; //编译通过,分配int(‘a’)个字节的空字符串
s4和s5 分别把一个int类型和char类型,隐式转换成了分配若干字节的字符串。
为了避免这种错误的发生,我们要显示的转换,使用explicit关键字:
class String
{
public:
explicit String(int n);
String(const char * p);
};
加上explicit,就抑制String(int n)的隐式转换
这样就不允许:
String s4=10;
String s5= ‘a’;
因此,某些时候,explicit可以有效得防止构造函数的隐式转换带来的错误或误解。
2. C++中的四种类型转换操作符
2.1.static_cast
类似于C风格的强制转换。
1.基类和子类之间转换:其中子类指针转换成父类指针是安全的;但父类指针转换成子类指针是不安全的。(基类和子类之间的动态类型转换建议用dynamic_cast)
2. 基本数据类型转换。enum, struct, int, char, float等。static_cast不能进行无关类型(如非基类和子类)指针之间的转换。
3. 把空指针转换成目标类型的空指针。
4. 把任何类型的表达式转换成void类型。
5. static_cast不能去掉类型的const、volitale属性(用const_cast)。
例如:
float x;
….
cout<<static_cast<int>(x);
2.2.dynamic_cast
将多态型别向下转型:
将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理,
即会作一定的判断。
对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针;
对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用。
注意:dynamic_cast在将父类cast到子类时,父类必须要有虚函数。
例如:
class Car;
class Cabriolet: public Car
{
};
class Limousine : public Car
{
};
void f(Car *cp)
{
Cabriolet *p=dynamic_cast<Cabriolet *>(cp);
if(p==NULL)
{
//转换失败
}
}
2.3const_cast
去掉类型的const或volatile属性。
2.4.reinterpret_cast
reinterpret_cast 任意两种指针类型之间,指针和数值类型直接的转换,最危险的一种转换
综合例子:
#include<iostream>
using namespace std;
#include<cstdlib>
int main()
{
intn=static_cast<int>(45.67); //double类型的数45.67转换为int类型的,相当于
//int n=(int)45.67
int *p=static_cast<int*>(calloc(sizeof(int),10))//相当于强制转换的
//int *p=(int *)........
const int k=n;
cout<<"k="<<k<<endl;
const_cast<int&>(k)=789; //const_cast 临时去掉const类型 这是k可以修改
//转换为一个int的引用类型的k 为左值可以赋值给他修改他
cout<<"k="<<k<<endl; //输出结果为: k=789
float f=123.45;
p=reinterpret_cast<int*>(&f);
cout<<*p<<endl; //
n=int(12.34); //一种转换的方法 double转化为int类型
n=int(); //输出的n的结果为0
//变量的初始化:
int m(100); //变量的一种初始化的方法
cout<<"m="<<m<<endl;
}