学习笔记:C++RTTI(dynamic-创新互联

文章目录
  • 一.dynamic_cast
    • 1.为什么需要dynamic_cast
    • 2.dynamic_cast的使用形式
    • 3. 代码示例
      • 3.1 类定义
      • 3.2 通过派生类指针调用基类的方法
      • 3.3 通过指向派生类的基类指针调用派生类A有而派生类B没有的方法
      • 3.4 引用版本
  • 二. typeid
    • 1.用途
    • 2.用法
    • 3.代码示例
  • 四.参考文献

阳新ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为成都创新互联的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:18982081108(备注:SSL证书合作)期待与您的合作!一.dynamic_cast 1.为什么需要dynamic_cast
  • 首先看dynamic_cast的定义:dynamic_cast是一个运算符,用于将基类的指针或引用安全地转换成派生类的指针或引用。注意:这里的安全仅针对转换结果,而不针对过程。如果转换成功的话,后续使用才是安全的。
  • 从上面的定义中,我们很容易联想到另外一种基类指针转换成派生类指针的用法也就是虚函数。基类定义虚函数,后续用一个指向派生类的基类指针调用该函数,这种场景是绝对安全的,这种安全由编译器保证,编译器将根据对象的动态类型自动选择正确的函数版本。但是如果想执行以下两种操作,编译器无法再做安全的保证,这时候就需要用dynamic_cast做显示转换了。
    ①通过派生类指针调用基类的方法;
    ②通过指向派生类的基类指针调用派生类A有而派生类B没有的方法;
2.dynamic_cast的使用形式
  • dynamic_cast(e)
  • dynamic_cast(e)
  • dynamic_cast(e)
    在上面的所有形式中,e的类型必须符合以下3个条件中的任意一个:e的类型必须是目标type的公有派生类,e的类型是目标type的公有基类或者e的类型就是目标type的类型,如果符合,则转换可以成功,否则失败。如果一条dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0.如果转换目标是引用类型并且失败了,则抛出异常std::bad_cast.
    NOTE:dynamic_cast转换中基类必须包含至少一个虚方法
3. 代码示例 3.1 类定义
class Base {public:
    Base() = default;
    ~Base() = default;

    virtual void Hello() {std::cout<< "Hello"<< std::endl;
    }

    void Func() {std::cout<< "Func with Base"<< std::endl;
    }
};

class DervideA:public Base {public:
    DervideA() = default;
    ~DervideA() = default;

    void Hello() override {std::cout<< "Hello A"<< std::endl;
    }

    void doSomething() {std::cout<< "do something"<< std::endl;
        return;
    }

    void Func() {std::cout<< "Func with DervideA"<< std::endl;
    }
};

class DervideB:public Base {public:
    DervideB() = default;
    ~DervideB() = default;

    void Hello() override{std::cout<< "Hello B"<< std::endl;
    }

    void Func() {std::cout<< "Func with DervideB"<< std::endl;
    }
};
3.2 通过派生类指针调用基类的方法
int main() {DervideA *pDervideA = new (std::nothrow) DervideA;
    if (pDervideA) {pDervideA->Func();
        //场景一:派生类指针转换为基类指针,使用基类的方法
        if (Base *pBase = dynamic_cast(pDervideA)) {pBase->Func();
        }
    }
    delete pDervideA;

    return 0;
}
  • 运行结果:
[root@VM-8-15-centos c++]# ./../../../bin/RTTI_test_demo 
Func with DervideA
Func with Base
3.3 通过指向派生类的基类指针调用派生类A有而派生类B没有的方法
void Hello(Base *pBase) {//基类的虚函数,编译器保证的安全的保证
    pBase->Hello();
    //场景二:基类指针转换指定的派生类指针
    //doSomething方法仅在DervideA中有,无法直接通过pBase使用。可以将基类指针通过dynamic_cast转换成DervideA的指针进行使用
    //如果pBase是指向DervideB的,则转换失败
    DervideA *pDervideA = dynamic_cast(pBase);
    if (pDervideA)
        pDervideA->doSomething();
    else
        std::cout<< "dynamic_cast failed!"<< std::endl;
}

int main() {Base *p = new (std::nothrow) DervideA;
    if (p)
        ::Hello(p);
    delete p;

    p = new (std::nothrow) DervideB;
    if (p)
        ::Hello(p);
    delete p;

    return 0;
}
  • 运行结果:
[root@VM-8-15-centos c++]# ./../../../bin/RTTI_test_demo 
Hello A
do something
Hello B
dynamic_cast failed!
3.4 引用版本
void Hello(Base& refBase)
{refBase.Hello();
    //场景二:基类引用转换指定的派生类引用
    //doSomething方法仅在DervideA中有,无法直接使用。可以将基类引用通过dynamic_cast转换成DervideA的引用进行使用
    //如果转换失败,抛出异常std::bad_cast
    try
    {DervideA& refDervideA = dynamic_cast(refBase);
        refDervideA.doSomething();
    }
    catch(const std::exception& e)
    {std::cout<< "dynamic_cast failed!"<< std::endl;
        std::cerr<< e.what()<< '\n';
    }
}

int main()
{Base *p = new (std::nothrow) DervideA;
    if (p)
        ::Hello(*p);
    delete p;

    p = new (std::nothrow) DervideB;
    if (p)
        ::Hello(*p);
    delete p;

    DervideA *pDervideA = new (std::nothrow) DervideA;
    if (pDervideA) {pDervideA->Func();
        //场景一:派生类引用转换为基类引用,使用基类的方法
        try
        {Base& refBase = dynamic_cast(*pDervideA);
            refBase.Func();
        }
        catch(const std::exception& e)
        {std::cout<< "dynamic_cast failed!"<< std::endl;
            std::cerr<< e.what()<< '\n';
        }
    }
}

运行结果:

[root@VM-8-15-centos c++]# ./../../../bin/RTTI_test_demo 
Hello A
do something
Hello B
dynamic_cast failed!
std::bad_cast
Func with DervideA
Func with Base
二. typeid 1.用途
  • 获取对象的类型
2.用法
  • typeid的表达式形式是typeid(e),其中e可以是任意表达式或者类型的名字。typeid操作的结果是一个常量对象的引用,该对象的类型是标准库类型type_info或者type_info的公有派生类类型,type_info类定义在typeinfo头文件中。
  • typed运算符可以用于任意类型的表达式,和往常一样,顶层const被忽略,如果表达式是一个引用,则typeid返回该引用所引对象的类型。不过当typeid作用于数组或者函数时,并不会执行向指针的标准类型转换。对于数组a执行typeid(a),则所得的结果是数组类型而非指针类型。
  • 当运算对象不属于类类型或者是一个不包含任何虚函数的类时,typeid运算符指示的是运算对象的静态类型。而当运算对象的类包含虚函数时,typeid的结果直到运行时才会求得。
  • NOTE:对一个对象指针做typeid运算是无意义的,得到的结果是指针类型而非指针指向对象的类类型
3.代码示例
void typeid_test(Base *pBase)
{//typeid对象指针无法获取指针所指对象的类类型
    if (typeid(pBase) == typeid(Base))
        std::cout<< "Base"<< std::endl;
    
    //typeid对象或其引用得出的结果才是对象的类型 
    if (typeid(*pBase) == typeid(DervideA)) {std::cout<< "DervideA"<< std::endl;
    }
    else if (typeid(*pBase) == typeid(DervideB)) {std::cout<< "DervideB"<< std::endl;
    }
}

int main()
{int array[] = {1,2,3};
    //typeid一个数组的结果不是数组类型的指针
    if (typeid(array) == typeid(int*))
        std::cout<< "type of array is int-pointer!"<< std::endl;
    else
        std::cout<< "type of array is not int-pointer!"<< std::endl;
    
    Base *p = new (std::nothrow) DervideA;
    if (p)
        :: typeid_test(p);
    delete p;

    p = new (std::nothrow) DervideB;
    if (p)
        ::typeid_test(p);
    delete p;

    return 0;
}
  • 运行结果:
[root@VM-8-15-centos c++]# ./../../../bin/RTTI_test_demo
type of array is not int-pointer!
DervideA
DervideB
四.参考文献

C++ Primer 第五版

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


本文标题:学习笔记:C++RTTI(dynamic-创新互联
转载源于:http://cdiso.cn/article/ccpies.html

其他资讯