C++ 向上与向下类型转换(static_cast与dynamic_cast)

隐式转型(向上转型,即将派生类对象赋值给基类)

C++允许向上转型,即将派生类的对象赋值给基类的对象是可以的,其只不过是将派生类中基类的部分直接赋给基类的对象,这称为向上转型(此处的“上”指的是基类),例如:

class Base{ };
class Derived : public base{ };
Base* Bptr;
Derived* Dptr;
Bptr = Dptr; //编译正确,允许隐式向上类型转换
Dptr = Bptr;//编译错误,C++不允许隐式的向下转型;

但是编译正确不代表能够使得程序安全运行。这很好理解,如果你把一个指向Base类对象的指针赋值 给一个Drived类类型的指针,如果这个指针去访问Drived类中存在而Base类中不存在成员,很明显就不安全了。
所以一个更好的办法是使用dynamic_cast;

向下转型

正如上面所述,类层次间的向下转型是不能通过隐式转换完成的。此时要想达到这种转换,可以借助static_cast 或者dynamic_cast。

通过static_cast完成向下转型

例如:

class Base{ };
class Derived : public base{ };
Base* B;
Derived* D;
D = static_cast<Drived*>(B); //正确,通过使用static_cast向下转型

需要注意的是:static_cast的使用,当且仅当类型之间可隐式转化时,static_cast的转化才是合法的。有一个例外,那就是类层次间的向下转型,static_cast可以完成类层次间的向下转型,但是向下转型无法通过隐式转换完成!

通过dynamic_cast完成向下转型

和static_cast不同,dynamic_cast涉及运行时的类型检查。如果向下转型是安全的(也就是说,如果基类指针或者引用确实指向一个派生类的对象),这个运算符会传回转型过的指针。如果downcast不安全(即基类指针或者引用没有指向一个派生类的对象),这个运算符会传回空指针。
ps:要使用dynamic_cast类中必须定义虚函数

class Base{
publicvirtual void fun(){} 
 };
class Drived : public base{
public:
	int i;
 };
Base *Bptr = new Drived()//语句0
Derived *Dptr1 = static_cast<Derived *>(Bptr); //语句1;
Derived *Dptr2 = dynamic_cast<Derived *>(Bptr); //语句2;

此时语句1和语句2都是安全的,因为此时Bptr确实是指向的派生类,虽然其类型被声明为Base*,但是其实际指向的内容确确实实是Drived对象,所以语句1和2都是安全的,Dptr1和Dptr2可以尽情访问Drived类中的成员,绝对不会出问题。
但是此时如果将语句0改为这样:

Base *Bptr = new Base()

那语句1就不安全了,例如访问Drived类的成员变量i的值时,将得到一个垃圾值。(延后了错误的发现)
语句2使得Dptr2得到的是一个空指针,对空指针进行操作,将发生异常,从而能够尽早的发现错误,这也是为什么说dynamic_cast更安全的原因。

多继承时的向下转型

class Base1{
	virtual void f1(){}
}class Base2{
	virtual void f2(){}
};
class Derived: public Base1, public Base2{
	void f1(){}
	void f2(){}
};
Base1 *pD = new Derived;
Derived *pD1  = dynamic_cast<Derived*>(pD);  //正确,原因和前面类似
Derived *pD2  = static_cast<Derived*>(pD);  //正确,原因和前面类似
Base2 *pB1  = dynamic_cast<Base2*>(pD);    //语句1
Base2 *pB2  = static_cast<Base2*>(pD);    //语句2

此时的语句1,将pD的类型转化为Base2*,即:使得pB1指向Drived对象的Base2子对象,为什么能达到这种转化?因为dynamic_cast是运行时才决定真正的类型,在运行时发现虽然此时pD的类型是Base1*,但是实际指向的是Derived类型的对象,那么就可以通过调整指针,来达到pB1指向Derived 对象的Base2子对象的目的;

但是语句2就不行了,其使用的是static_cast,它不涉及运行时的类型检查,对于它来讲,pD的类型是Base1*,Base1和Base2没有任何关系,那就会出现编译错误了。error: invalid static_cast from type ‘Base1*’ to type ‘Base2*’

总结:对于多种继承,如果pD真的是指向Derived,使用static_cast和dynamic_cast都可以转化为Derived,但是如果要转化为Base1的兄弟类Base2,必须使用dynamic_cast,使用static_cast不能通过编译。

ps:因为Derived和Base1和Base2*之间存在隐式转化,可以将语句2修改为:

Base2 *pB2 = static_cast<Base2*>(static_cast<Derived*>(pD));

这样就可以完成转换。

转载自:(有少量修改)
————————————————
版权声明:本文为CSDN博主「十一月zz」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/baidu_35679960/article/details/80821222

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读