类型转换(Type casting)
1 //首先简单介绍下C++默默为我们生成和调用的函数 2 class Empty {}; 3 //如果你写上面的code, C++编译器会为你生成下面的code 4 class Empty{ 5 public: 6 Empty() {...} //default 构造函数 7 Empty(const Empty& rhs) {...} //copy 构造函数 8 ~Empty() {...} // 析构函数 9 10 Empty& operator= (const Empty& rhs) {...} //copy assignment 操作符 11 }; 12 13 //具体发生调用的情况如下 14 Empty e1; //default 构造函数 15 //析构函数 16 Empty e2(e1); //copy 构造函数 17 Empty e3 = e1; //copy 构造函数 但是推荐用上面的格式 18 19 e2 = e1; //copy assignment 操作符
隐含的类型转换(Implicit conversion)
隐含的类型转换不需要任何操作符,它们自动转换。
1)一些基本类型的转换,such as( short to int, int to float, double to int ...)
1 short a = 2000; 2 int b; 3 b=a;
2)派生类和基类之间的指针和引用转换,以及对象转换 ( 派生类 ----转换到----》 基类)
1 class A{}; 2 class B : public A{}; 3 4 A& ra = B(); //OK: B& rb = A() is error. 5 A* pa = new B(); //OK: B* pb = new A() is error. 6 7 A a1; 8 B b1; 9 a1 = b1 //ok 10 b1 = a1 // error. can't compile.
3)构造函数和操作符的隐含转换
---
c++中explicit关键字的含义和用法
c++中的explicit关键字用来修饰类的构造函数,表明该构造函数是显式的, 既然有"显式"那么必然就有"隐式",那么什么是显示而什 么又是隐式的呢?
如果c++类的构造函数有一个参数,那么在编译的时候 就会有一个缺省的转换操作:将该构造函数对应数据类型的数据转换为该类对象 ,如下面所示:
class MyClass {
public: MyClass( int num );
}
.... MyClass obj = 10; //ok,convert int to MyClass
在上面的代码中编译器自动将整型转换为MyClass类对象,实际上等同于下面的操 作:
MyClass temp(10);
MyClass obj = temp;
上面的 所有的操作即是所谓的"隐式转换".
如果要避免这种自动转换 的功能,我们该怎么做呢?嘿嘿这就是关键字explicit的作用了,将类的构造函 数声明为"显示",也就是在声明构造函数的时候 前面添加上explicit 即可,这样就可以防止这种自动的转换操作,如果我们修改上面的MyClass类的构 造函数为显示的,那么下面的代码就不能够编 译通过了,如下所示:
class MyClass {
public: explicit MyClass( int num );
}
.... MyClass obj = 10; //err,can't non-explict convert
C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。声明为explicit的构造函数不能在隐式转换中使用。 C++中, 一个参数的构造函数, 承担了两个角色。 1 是个构造器 2 是个默认且隐含的类型转换操作符。 所以, 有时候在我们写下如 AAA = XXX, 这样的代码, 且恰好XXX的类型正好是AAA单参数构造器的参数类型, 这时候编译器就自动调用这个构造器, 创建一个AAA的对象。 这样看起来好象很酷, 很方便。 但在某些情况下(见下面权威的例子), 却违背了我们(程序员)的本意。这时候就要在这个构造器前面加上explicit修饰, 指定这个构造器只能被明确的调用,使用, 不能作为类型转换操作符被隐含的使用。 explicit构造函数的作用 解析: explicit构造函数是用来防止隐式转换的。请看下面的代码:
class Test1 {
public:
Test1(int n) { num = n; } //普通构造函数
private: int num;
};
class Test2 {
public:
explicit Test2(int n) { num = n; } //explicit(显式)构造函数
private: int num;
};
int main()
{
Test1 t1 = 12; //隐式调用其构造函数, 成功
Test2 t2 = 12; //编译错误,不能隐式调用其构造函数
Test2 t3(12); //显示调用成功
return 0;
}
Test1的构造函数带一个int型的参数,代码19行会隐式转换成调用Test1的这个构造函数。而Test2的构造函数被声明为explicit(显式),这表示不能通过隐式转换来调用这个构造函数,因此代码20行会出现编译错误。 普通构造函数能够被隐式调用。而explicit构造函数只能被显示调用。
1 class A {}; 2 class B { 3 public: 4 B(A a) {} 5 }; 6 7 A a; 8 B b=a; // first, 利用a调用构造函数生成,second, 调用copy构造函数生成b 9 10 // 如果想阻止这样的隐含调用发生,必须使用explicit 在B 的构造用函数处。
显示调用转换(Explicit conversion)
1) 传统的显示调用
a)一些基本类型的转换,以及派生类和基类之间的指针和引用转换,以及对象转换 ( 派生类 ----转换到----》 基类)
1 short a =2000; 2 int b; 3 b = (int) a; //C-like cast notation 4 b = int(a); //functional notation
b)任意指针类型之间的转换 和引用类型之间的转换:可能导致 run-time error or a unexpected result.
1 class CDummy 2 { float i,j;}; 3 class CAddition 4 { 5 int x,y; 6 public: 7 CAddition(int a, int b) {x=a; y = b;} 8 int result() {return x+y;} 9 }; 10 int main(){ 11 CDummy d; 12 CAddition *padd; 13 padd = (CAddition*)&d; //指针
CAddition &rpadd = (CAddition&)d; //引用 14 cout<<padd->result(); // 这样会导致出错,产生不正确的结果 15 return 0; 16 }
2)为了控制 类(class)之间的合法转换,引入4个指定的类型转换操作符:dynamic_cast, reinterpret_cast,static_cast and const_cast.
格式: dynamic_cast<new_type> (expression)
传统的显示类型转换格式:
(new_type) expression
new_type (expression)
其中只有dynamic_cast转换发生在运行时,动态的,其他3种都是在编译时期。
dynamic_cast requires the Run-time Type information(RTTI) to keep track of dynamic types.
a) dynamic_cast
只被用于 class的引用和指针,可以确保类型转换是不是一个完整的object.所以 “派生类---转换到---》基类”永远成功。
//1. 只能在继承对象的指针之间和引用之间进行类型转换,基类 到 派生类的转换 :当类不是多态的,(编译失败,产生编译错误); 当类是多态的(编译成功),但是不是一个完整的object: 转换指针时候 ,return NUll pointer. 转换引用时候, throw bad_cast exception.
//2. 没有继承关系,但是被转换的类必须具有虚函数 。这时候这个对象的指针可以进行转换.(可以编译成功)
1 derv* dp=new derv; 2 Base* bv=dynamic_cast<Base *>(dp);//继承类对象的指针之间进行类型转换 3 4 derv dpp;//继承类对象引用之间进行类型转换 5 Base &b=dynamic_cast<Base&>(dpp); 6 7 class AA{virtual fun(){} 8 virtual ~AA(){}}; 9 class BB{}; 10 11 //没有继承关系,但被转换的类具有虚函数对象的指针进行转换,编译可通过 12 AA* pAA=new AA; 13 BB* pBB=dynamic_cast<BB *>(pAA); 14 15 //没有继承关系,被转换的类也没有有虚函数对象的指针进行转换,编译不能通过 16 BB* pBBB=new BB; 17 AA* pAAA=dynamic_cast<AA*>(pBBB);
b) reinterpret_cast
//1.将一个类型指针转换为另一个类型指针,这种转换不修改指针变量值数据存放格式
//2.只需在编译时重新解释指针的类型,他可以将指针转化为一个整型数但不能用于非指针的转换
但是发现也可以用于引用转换
c) const_cast
用于指针和引用的转换
//1.用于去除指针变量的常属性,将它转换为一个对应指针类型的普通变量,
//2.反过来也可以将一个非常量指针转换为一个常量指针变量
//3.他无法将一个非指针的常量转换为普通变量
d) static_cast
类似于传统的显示调用
//1.用于转换基本类型和具有继承关系的类新之间转换
//2.static_cast不太用于指针类型的之间的转换,他的效率没有reinterpret_cast的效率高
总结:
- reinterpret_cast 主要是用来将一个类型指针转换为另一个类型指针
- const_cast 主要是用来用于去除指针变量的常属性,将它转换为一个对应指针类型的普通变量,反过来也可以将一个非常量指针转换为一个常量指针变量
- static_cast 主要是用来 用于转换基本类型和具有继承关系的类新之间转换,不太用于指针类型的之间的转换
- dynamic_cast 主要是用来只能在继承类对象的指针之间或引用之间进行类型转换
浙公网安备 33010602011771号