类型转换(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    主要是用来只能在继承类对象的指针之间或引用之间进行类型转换

posted on 2013-01-08 17:11  code.life  阅读(350)  评论(0)    收藏  举报

导航