RTTI 基本概念

RTTI

dynamic_cast 和type_id特别适用于 对基类指针引用执行某个派生类操作而该派生类操作不是虚函数(非常拧巴)
与虚函数成员相比RTTI有潜在风险

基本例子, 基类至少含有要一个虚函数否则报错cannot dynamic_cast ‘ptr’ (of type ‘class Father*’) to type ‘class son*’ (source type is not polymorphic)

class Father{
    //基类至少有一个虚函数
    virtual void func(void){}
};
class son:public Father{

};

int main(){
    Father * ptr = new son();
    if(son* dp = dynamic_cast<son *>(ptr))
    {
        cout << "RTTI\n";
    }
    else{
        cout<<"failed\n";
    }
return 0;
}

RTTI 引用例子

void f(const Father & rf){
    try{
        const son & rs = dynamic_cast<const son &>(rf);
        cout <<"RTTI ok\n";
    }
    catch(...){
        cout <<"nothing";
    }
    return;
}

typeid比较动态对象

下面很重要

  • typeid作用域指针时 需要确保对象存在,否则会抛错"bad_typeid",用之前最好判断一下指针是否非null
  • typeid和dyanmaic_cast一样,需要至少一个虚函数存在于基类
  • typeid如果作用域指针(而非指针对象)返回结果是该指针静态类型

typeid比较(指针和引用的)动态对象

 //typeid用于比较指针的动态对象
    Father *pf = new son();
    son * ps = new son();
    cout << boolalpha << (typeid(*pf)==typeid(*ps)) << endl;//true 两者指向同一动态对象
    //typeid用于比较引用的动态对象
    Father & rf = (*pf);
    son & rs = (*ps);
    cout << boolalpha << (typeid(rf)==typeid(rs)) << endl;//true

注意如果上述son *ps = nullptr;会抛错std::bad_typeid这种比较需要确保对象存在。
如果只想确定类型可以用typeid和类型比较

typeid比较对象和类型

也要确保对象存在,否则会跑错

Father *pf = new son;
    
    if (typeid(*pf)==typeid(son))
    {
        cout << "son\n";
        /* code */
    }
    else if(typeid(*pf)==typeid(Father))
    {
        cout << "Father\n";
    }

typeid如果作用域指针(而非指针对象)返回结果是该指针静态类型

//typeid用于比较指针本身而非对象
    Father *pf = new son;
    
    if (typeid(pf)==typeid(son*))
    {
        cout << "son\n";
        /* code */
    }
    else if(typeid(pf)==typeid(Father*))
    {
        cout << "Father pointer \n";
    }
    

typeid和std::type_info

  • typeid是个operatorhttps://en.cppreference.com/w/cpp/language/typeid
  • std::type_info是个STL库类 存在于头文件下 https://www.cplusplus.com/reference/typeinfo/type_info/
    type_info用来打类型
int i;
  int * pi;
  std::cout << "int is: " << typeid(int).name() << '\n';
  std::cout << "  i is: " << typeid(i).name() << '\n';
  std::cout << " pi is: " << typeid(pi).name() << '\n';
  std::cout << "*pi is: " << typeid(*pi).name() << '\n';

输出

int is: i
  i is: i
 pi is: Pi
*pi is: i

使用RTTI

  • Primer19.2.3 相等运算符例子

相等运算符

目的是定义一套相等运算符,Base对比Base,Derived对比Derived
如果相等运算符读入Base指针,只能比较Base对象
equal包了类对象的所有成员的比较

class Base{
    //友元相等运算符 友元是基类自己的友元
    friend bool operator==const Base &,const Base&);
protected:
    virtual bool equal(const Base &) const;//比较
};
class Derived:public Base{

protected:
    //virtual函数必须保持形参一致,即使派生类也只能用基类引用类型做入参
    virtual bool equal(const Base &) const;//比较

};
bool operator==(const Base & lhs,const Base &rhs){
    //rtti确保动态类型一致
    //调用的equal和lhs的动态类型一致
    return typeid(lhs)==typeid(rhs)&&lhs.equal(rhs);
}
//别忘了 virtual和不出现在函数外
bool Derived::equal(const Base &rhs){
    //必须类型转换的原因 只有使用派生类引用才能对比派生类独有对象
    auto r = dynamic_cast<const Derived &>(rhs);

}

把几个例子填满


class Base{
    //友元相等运算符 友元是基类自己的友元
    friend bool operator==(const Base &,const Base&);
protected:
    virtual bool equal(const Base &) const;//比较
public:
    string name;
    Base(const string &n):name(n){}
   
};
class Derived:public Base{

protected:
    //virtual函数必须保持形参一致,即使派生类也只能用基类引用类型做入参
    virtual bool equal(const Base &) const;//比较



public:
    double thre;
    Derived(const string &n,const double & t):Base(n),thre(t){}
};


//别忘了 virtual和不出现在函数外
bool Derived::equal(const Base &rhs) const {
    //必须类型转换的原因 只有使用派生类引用才能对比派生类独有对象
    auto r = dynamic_cast<const Derived &>(rhs);
    return (this->name==rhs.name)&&(this->thre==r.thre);

}
bool Base::equal(const Base &rhs) const {
    return this->name==rhs.name;
}

bool operator==(const Base & lhs,const Base &rhs){
    //rtti确保动态类型一致
    //调用的equal和lhs的动态类型一致
    return typeid(lhs)==typeid(rhs)&&lhs.equal(rhs);}
int main(){
    Base ba("Alice"),bb("Jack");
    Derived da("Migi",0.4),db("Jack",0.4),dc("Migi",0.4);
    cout<<boolalpha <<(da==dc)<<endl;
    cout<<boolalpha <<(bb==db)<<endl;
    cout<<boolalpha <<(ba==bb)<<endl;

    
return 0;
}

参考

Primer

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值