浅谈C++新式转型操作符

 

浅谈新式转型操作符:

 

const_cast

                             

#include "stdafx.h"

#include <IOSTREAM>

#include "Animal.h"

#include "Cat.h"

using namespace std;

int main(int argc, char* argv[])

{

 const CCat mycat;

 Animal* cat=&mycat;

 cat->eat();

 return 0;

}


 

 

上面代码Animal是基类,并且有一个eat的虚方法,CCat派生于Animal并实现了eat方法。

在运行如上代码时,毋庸置疑会发生错误。cannot convert from 'const class CCat *' to 'class Animal *'

所以利用旧式转型操作,可以很简单的避免这个错误,作如下类型转换:

#include "stdafx.h"

#include <IOSTREAM>

#include "Animal.h"

#include "Cat.h"

using namespace std;

int main(int argc, char* argv[])

{

 const CCat mycat;

 Animal*cat=(Animal*)&mycat;

 cat->eat();

 return 0;

}


 

仔细考虑,上面代码其实做了两个转型,一个是去除了mycat的const,另一个将*CCat转换成了*Animal.

这看上去很正确,但考虑下面代码:

我们新增一个Person类,人不是动物所以无须继承Animal类。

int main(int argc, char* argv[])

{

 const CCat mycat;

 Person*p=(Person*)&mycat;

 return 0;

}


 

但上面的代码依然是编译通过的。这不就是cat is a person.然后利用const_cast进行转换时

 

int main(int argc, char* argv[])

{

 const CCat mycat;

 Person*p=const_cast<Person*>(&mycat);

 return 0;

}

//或

int main(int argc, char* argv[])

{

 const CCat mycat;

 Person*p=const_cast<CCat*>(&mycat);

 return 0;

}


编译时

cannot convert from 'class CCat *' to 'class Person *'

 

看到这里,读者可能有点感觉了,对于旧式的转换操作,他并不检查类型不正确转换,简单的说就是告诉编译器“喂,给我把const cat转成person”,而const_cast转换操作则相对威力更小,因为它只影响类型修饰符,这样的限制同样是件好事,因为他更能精确的表达我们的意图。在const cat到person时,他只能把const去除,一旦到类型转换时,他就无能为力,编译发现类型不匹配时则会报错。

 

static_cast最常用的将一个继承层次结构中的基类指针或引用,向下转型成派生类的指针或引用。需要注意的是必须是继承层次中。

 

所以对于

Animal* an=new CCat;

CCat*cat=(CCat*)&an;

实际上由这个两步完成

Animal* cat2=const_cast< Animal*>(&mycat);

CCat * cat2=static_cast< CCat *>(&mycat);

 

Reinterpret_cast指它是从bit看待一个对象。从而允许将一个东西看作另一个完全不同的东西。他在低层编码时偶尔非用不可,但不具备移植性。当使用reinterpret_cast和static_cast将指向基类的指针向下转型为指向派生类的指针时的行为。Reinterpret_cast通常只是将基类指针假装成一个派生类指针而不改变其值,而static_cast和旧式转型则将执行正确的地址操作。

Animal* an=new Animal;

CCat*cat=reinterpret_cast<CCat*>(an);

cat->eat();

//此处cat虽然声明类型为CCat*,但终将是假装(实质还是Animal*),最终打印的还是//Animal eat.

CCat*cat2=static_cast<CCat*>(an);

cat2->eat();

//因为static_cast进行内存转换,cat2已经货真价实的CCat*了。

 

Dynamic_cast仅用于对多态类型进行向下转型,即被转型的表达式类型,必须是带有一个指向虚函数的类型的指针,并且进行运行期检查工作,而static_cast则无须付出这种代价。对指针类型进行向下转型时,转型失败会返回null,而对于引用指针类型向下转型时,转型失败则会引起异常。

Animal* an=new Cat;

 if (Person* cat=dynamic_cast<Person*>(an))

 {

    std::cout<<"castsuccess"<<std::endl;

 }else

 {

 std::cout<<"castfailed"<<std::endl;

 }


 

当转型成功时会返回正确指针对象,转型错误时则会返回null作为if条件。但是在vc6.0中以下代码虽然编译能通过,但执行时确会报错,而在vs2005中则正确输出。

Cat an;

Animal& refan=an;

Person& cat=dynamic_cast<Person&>(refan);

return 0;

 

 

对了,至于引用不能作为if判断条件,很简单,引用不能为空,引用一旦声明就必须初始化。但考虑如下:



   const int&a=2;

   const int&b=NULL;

   if (b==NULL)

   {

      std::cout<<"b is null"<<std::endl;

 }


 

这确是可以的,当一个指向常量的引用采用一个字面值来初始化,该引用实际上被设置指向“采用该字面值初始化”的一个临时位置。因为a,b并非真的指向字面值,而是指向一个采用字面值初始化、类型为int的的临时量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值