澳门新葡萄京官网注册C++标准转换运算符dynamic_cast(转)

dynamic_cast <new_type> (expression)

dynamic_cast运算符,应该算四只里面太奇特的一个,因为其事关到编译器的属性设置,而且关到的面向对象的多态性跟程序运行时之状态吧时有发生涉及,所以不能够完全的利用传统的换方式来代表。但是呢为此它是无比常用,最不可缺失的一个运算符。

与static_cast一样,dynamic_cast的更换为待目标项目和源对象有必然之关联:继承关系。
更规范的游说,dynamic_cast是因此来检查两者是否发延续关系。因此该运算符实际上只接受基于类对象的指针和援的近乎易。从这个方面来拘禁,似乎dynamic_cast又和reinterpret_cast是一样的,但骨子里,它们要有着挺挺之出入。

或者用代码来分解,让编译器来验证吧。

/////////////////////////////////////////////////////////////////////////////
// cast_operator_comparison.cpp                                                      
// Language:   C++                   
// Complier:    Visual Studio 2010, Xcode3.2.6 
// Platform:    MacBook Pro 2010
// Application:  none  
// Author:      Ider, Syracuse University  ider.cs@gmail.com
///////////////////////////////////////////////////////////////////////////
#include <string>
#include <iostream>
using namespace std;

class Parents
{
public:
    Parents(string n="Parent"){ name = n;}
    virtual ~Parents(){}

    virtual void Speak()
    {
        cout << "\tI am " << name << ", I love my children." << endl;
    }
    void Work()
    {
        cout << "\tI am " << name <<", I need to work for my family." << endl;;
    }
protected:
    string name;
};

class Children : public Parents
{
public:
    Children(string n="Child"):Parents(n){ }

    virtual ~Children(){}

    virtual void Speak()
    {
        cout << "\tI am " << name << ", I love my parents." << endl;
    }
    /*
     **Children inherit Work() method from parents,
     **it could be treated like part-time job.
     */
    void Study()
    {
        cout << "\tI am " << name << ", I need to study for future." << endl;;
    }

private:
    //string name; //Inherit "name" member from Parents
};

class Stranger 
{
public:
    Stranger(string n="stranger"){name = n;}
    virtual ~Stranger(){}

    void Self_Introduce()
    {
        cout << "\tI am a stranger" << endl;
    }
    void Speak()
    {
        //cout << "I am a stranger" << endl;
        cout << "\tDo not talk to "<< name << ", who is a stranger." << endl;
    }
private:
    string name;
};

int main() {

    /******* cast from child class to base class *******/
    cout << "dynamic_cast from child class to base class:" << endl;
    Children * daughter_d = new Children("Daughter who pretend to be my mother");
    Parents * mother_d = dynamic_cast<Parents*> (daughter_d); //right, cast with polymorphism
    mother_d->Speak();
    mother_d->Work();
    //mother_d->Study(); //Error, no such method

    cout << "static_cast from child class to base class:" << endl;
    Children * son_s = new Children("Son who pretend to be my father");
    Parents * father_s = static_cast<Parents*> (son_s); //right, cast with polymorphism
    father_s->Speak();   
    father_s->Work();
    //father_s->Study(); //Error, no such method

    cout << endl;

    /******* cast from base class to child class *******/    
    cout << "dynamic_cast from base class to child class:" << endl;
    Parents * father_d = new Parents("Father who pretend to be a my son");
    Children * son_d = dynamic_cast<Children*> (father_d); //no error, but not safe
    if (son_d)
    {
        son_d->Speak();
        son_d->Study();
    }
    else cout << "\t[null]" << endl;

    cout << "static_cast from base class to child class:" << endl;
    Parents * mother_s = new Parents("Mother who pretend to be a my daugher");
    Children * daughter_s = static_cast<Children*> (mother_s);  //no error, but not safe
    if (daughter_s)
    {
        daughter_s->Speak();
        daughter_s->Study();
    }
    else cout << "\t[null]" << endl;

    cout << endl;

    /******* cast between non-related class *******/  
    cout << "dynamic_cast to non-related class:" << endl;
    Stranger* stranger_d = dynamic_cast<Stranger*> (daughter_d);
    if (stranger_d)
    {
        stranger_d->Self_Introduce();
        stranger_d->Speak(); 
    }
    else cout <<"\t[null]"<<endl;

    //Stranger* stranger_s = static_cast<Stranger*> (son_s);    //Error, invalid cast

    cout << "reinterpret_cast to non-related class:" << endl;
    Stranger* stranger_r = reinterpret_cast<Stranger*> (son_s);
    if (stranger_r)
    {
        stranger_d->Self_Introduce();
        //stranger_d->Speak(); //This line would cause program crush,
        //as "name" could not be found corretly.
    }
    else cout << "\t[null]" << endl;

    cout << endl;

    /******* cast back*******/
    cout << "use dynamic_cast to cast back from static_cast:" << endl;
    Children* child_s = dynamic_cast<Children*> (father_s);
    if (child_s)
    {
        child_s->Speak();
        child_s->Work();
    }
    else cout << "\t[null]" << endl;

    //cout<<typeid(stranger_r).name()<<endl;

    cout << "use dynamic_cast to cast back from reinterpret_cast:" << endl;
    Children* child_r = dynamic_cast<Children*> (stranger_r);
    if (child_r)
    {
        child_r->Speak();
        child_r->Work();
    }
    else cout << "\t[null]" << endl;

    delete daughter_d;
    delete son_s;
    delete father_d;
    delete mother_s;

    return 0;
}

/********************* Result *********************/

//dynamic_cast from child class to base class:
//    I am Daughter who pretend to be my mother, I love my parents.
//    I am Daughter who pretend to be my mother, I need to work for my family.
//static_cast from child class to base class:
//    I am Son who pretend to be my father, I love my parents.
//    I am Son who pretend to be my father, I need to work for my family.
//
//dynamic_cast from base class to child class:
//    [null]
//static_cast from base class to child class:
//    I am Mother who pretend to be a my daugher, I love my children.
//    I am Mother who pretend to be a my daugher, I need to study for future.
//
//dynamic_cast to non-related class:
//    [null]
//reinterpret_cast to non-related class:
//    I am a stranger
//
//use dynamic_cast to cast back from static_cast:
//    I am Son who pretend to be my father, I love my parents.
//    I am Son who pretend to be my father, I need to work for my family.
//use dynamic_cast to cast back from reinterpret_cast:
//    [null]

由上的代码和出口结果好看看:

对于自子类到基类的指针转换,static_cast和dynamic_cast都是成而对的(所谓成功是说易没有编译错误或运行很;所谓科学是因道的调用和数目的走访输出是望之结果),这是面向对象多态性的一应俱全体现。

若是从基类到子类的更换,static_cast和dynamic_cast
都是打响之,但是对方面,我对双方的结果还先进行了是否非空的辨认:dynamic_cast的结果显示是空指针,而static_cast则是非空
指针。但非常显著,static_cast的结果当算错误的,子类指针实际所倚的是基类的对象,而基类对象并无富有子类的Study()方法(除非妈妈
又想去领受个”继续教育”)。

对此没关联之少数个近乎中的换,输出结果表明,dynamic_cast依然是回一个空指针以象征转换是免起之;static_cast直接在编译期就拒绝了这种转移。

reinterpret_cast成功进行了变,而且回去的价值并无是空指针,但是结果肯定是漏洞百出的,因为Children类显然不享
Stranger的Self_Introduce()。虽然两者都具有name数据成员及Speak()方法,,Speak()方法呢只是是调用了该相同名
称的成员而已,但是对Speak()的调用直接促成了序的倒。

实际前面static_cast的转换的结果吗会见跟reinterpret_cast一样导致的先后的倒,只是看似的法门都只生同一份,只来数据成员属于对象,
所以在调用那些不见面访问对象的多少的计时(如Stranger的Self_Introduce())并无见面促成倒。而
daughter_s->Speak();和daughter_s->Study();调用了数码成员却并未出现运行错误,则是坐拖欠成员是
从基类继承下去的,通过地方偏移可以是的到数据成员所于的地点为朗诵取出数据。

末了,程序里还为此dynamic_cast希望将用任何转换运算符转换过去的指针转换回来。
对于利用static_cast转换后依为了子类对象的基类指针,dynamic_cast判定转换是合情合理实用之,因此转换成赢得一个非空的指针并且刚刚
确输出了结果;而对于reinterpret_cast转换的色,的确使她的效果雷同——重新分析,变成新的类,所以才得dynamic_cast
判定该类型已不是原来的档次结果,转换得到了一个空指针。

得说来,static_cast和reinterpret_cast运算符要么直接吃
编译器拒绝进行转移,要么就势必会取得相应的对象项目的价。
而dynamic_cast却会展开甄别,确定源指针所因的内容,是否确实适合被目标指针接受。如果是否定的,那么dynamic_cast则会回去
null。这是经检查”运行期类型信息”(Runtime type
information,RTTI)来判断的,它还受编译器的震慑,有些编译器需要装开启才能够让程序对运行(导师的PPT详尽介绍了Visual
Studio的图景),因此dynamic_cast也就未克因此传统的转移方式来贯彻了。

虚函数(virtual function)对dynamic_cast的作用

已当前边反复提到过面向对象的多态性,但是这多态性到底要如何体现吗?dynamic_cast真的兴擅自对象指针之间开展转移,只是最后回到个null值来报转换无结果吗?

其实,这一切都是虚函数(virtual
function)在从作用。

当C++的给对象考虑被,虚函数从及了老关键之来意,当一个看似吃有至少一个虚函数,那么编译器就会见构建有一个虚函数表(virtual
method
table)来指示这些函数的地址,假如继承该类的子类定义并促成了一个同名并有相同函数签名(function
siguature)的道更写了基类中的计,那么虚函数表会将拖欠函数指向新的地点。此时多态性就体现出了:当我们将基类的指针或引用指向子类的靶子的时光,调用方法时,就见面顺着虚函数表找到呼应子类的法子而无基类的办法。

本来虚函数表的在于效率及会见时有发生肯定的震慑,首先构建虚函数表需要时,根据虚函数表寻到到函数也用时间。

因为是缘故要没有继承的内需,一般不要在相近吃定义虚函数。但是对于继往开来来说,虚函数就易得稀重点了,这不仅仅是促成多态性的一个生死攸关标志,同时为是dynamic_cast转换能够进行的前提条件。

若果去丢上个例中Stranger类析构函数前的virtual,那么告诉句
Children* child_r = dynamic_cast<Children*> (stranger_r);

于编译期就见面直接报发出荒谬,具体由无是格外理解,我猜测可能是坐当类没有虚函数表的时段,dynamic_cast就未可知就此RTTI来确定类的现实性项目,于是就直接不经过编译。

眼看不光是从未继续关系的类中的景况,如果基类或者子类没有任何虚函数(如果基类有虚函数表,子类当然是全自动连续了该表),当她们当作dynamic_cast的源类型进行转换时,编译也会见败。

这种场面是发出或有的,因为当规划之上,我们可能不需要让子类更写任何基类的方式。但实则,这是未客观的。导师在教学多态性的时节,时刻强调了一些:如果如因此连续,那么早晚要于析构函数是虚函数;如果一个函数是虚函数,那么以子类中吗如是虚函数。

我会拿教师关于”为何连续中析构函数得是虚函数”的教授总结一下,当然你为堪拘留即时边文章来询问原因。

Director: Jim
Fawcett

  1. C++ Language Tutorial – Type
    Casting
  2. Object Oriented
    Design
  3. IBM Complilers – XL C/C++ V9.0 for Linux – The dynamic_cast
    operator (C++
    only)
  4. MSDN Visual C++ Develope Center – dynamic_cast
    Operator
  5. In C++, what’s a virtual destructor and when is it
    needed?
  6. Wikipedia The Free Encyclopedia – Run-Time Type
    Information
  7. Wikipedia The Free Encyclopedia – Virtual
    Function


http://www.cnblogs.com/ider/archive/2011/08/01/cpp\_cast\_operator\_part5.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注