【C/C++】【类和对象】RTTI和虚函数表

RTTI是什么

Run Time Type Identification:运行时类型识别;通过运行时类型识别,程序能够使用基类的指针或引用来检查这些指针或引用所指向的对象的实际派生类型。

Human *phuman = new Men;
Human &q = *phuman;

主要是通过两个运算符来实现的:

  1. dynamic_cast:能够将基类指针或者引用安全的转换为派生类的指针或者引用;
  2. typeid:返回指针或者引用所指对象的实际类型;
    注意
    要想让1和2正常工作,那么基类中必须至少有一个虚函数,否则这两个运算符的结果可能跟我们预想的不一样;因为只有虚函数的存在,这两个运算符才会使用指针或者引用所绑定的对象的动态类型(new的类型);

dynamic_cast

指针,如果转换成功,说明这个指针实际上是要转换到的那个类型;会做安全检查;

#include <iostream>
using namespace std;
class Human
{
public:
    Human();
    Human(int);
    virtual ~Human();
public:
    int m_Age;
    char m_Name[100];
public:
    virtual void eat() =0;
};
Human::Human()
{
    cout << "Human::Human()" << endl;
}
Human::~Human()
{
    cout << "Human::~Human()" << endl;
}
Human::Human(int tmp)
{
    cout << "Human::Human(int tmp)" << endl;
}
//Men是Human的子类
class Men:public Human
{
public:
    Men();
    Men(int);
    ~Men();
private:

public:
    virtual void eat();
};
Men::Men()
{
    cout << "Men::Men()" << endl;
}
Men::~Men()
{
    cout << "Men::~Men()" << endl;
}

Men::Men(int tmp)
{
    cout << "Men::Men(int tmp)" << endl;
}
void Men::eat()
{
    cout << "men eat mi" << endl;
}
//Women是Human的子类
class Women :public Human
{
public:
    Women();
    Women(int);
    ~Women();
private:

public:

    virtual void eat();
};

Women::Women()
{
    cout << "Women::Women()" << endl;
}
Women::~Women()
{
    cout << "Women::~Women()" << endl;
}

Women::Women(int tmp)
{
    cout << "Women::Women(int tmp)" << endl;
}


void Women::eat()
{
    cout << "women eat miantiao" << endl;
}
int main()
{
    //Men men;

    Human* p_m = new Men;
    Men* p_men = dynamic_cast<Men*>(p_m);
    if (p_men != nullptr)
        cout << "cast success! p_men is Men*" << endl;
    else
        cout << "cast fail! p_men is not Men*" << endl;
}

引用,如果用dynamic_cast转换失败,系统会抛出一个std::bad_cast异常;

#include <iostream> 
using namespace std;
class Human
{
public:
    Human();
    Human(int);
    virtual ~Human();
public:
    int m_Age;
    char m_Name[100];
public:
    virtual void eat() =0;
};

Human::Human()
{
    cout << "Human::Human()" << endl;
}
Human::~Human()
{
    cout << "Human::~Human()" << endl;
}

Human::Human(int tmp)
{
    cout << "Human::Human(int tmp)" << endl;
}




//Men是Human的子类
class Men:public Human
{
public:
    Men();
    Men(int);
    ~Men();
private:

public:
    virtual void eat();
};

Men::Men()
{
    cout << "Men::Men()" << endl;
}
Men::~Men()
{
    cout << "Men::~Men()" << endl;
}

Men::Men(int tmp)
{
    cout << "Men::Men(int tmp)" << endl;
}


void Men::eat()
{
    cout << "men eat mi" << endl;
}


//Women是Human的子类
class Women :public Human
{
public:
    Women();
    Women(int);
    ~Women();
private:

public:

    virtual void eat();
};

Women::Women()
{
    cout << "Women::Women()" << endl;
}
Women::~Women()
{
    cout << "Women::~Women()" << endl;
}

Women::Women(int tmp)
{
    cout << "Women::Women(int tmp)" << endl;
}


void Women::eat()
{
    cout << "women eat miantiao" << endl;
}


int main()
{

    //引用
    Human* phuman = new Men;
    Human& q = *phuman;
    try
    {
        Men& m = dynamic_cast<Men&>(q);
    }
    catch(std::bad_cast) //转换不成功
    {
        cout << "p is not Men!" << endl;
    }

    return 0;
}

typeid运算符

typeid(类型[指针/引用]/表达式);//得到对象类型信息

typeid会返回一个常量对象的引用,这个常量对象是一个标准库类型type_info(类/类类型);

#include <iostream>
using namespace std;
class Human
{
public:
    Human();
    Human(int);
    virtual ~Human();
public:
    int m_Age;
    char m_Name[100];
public:
    virtual void eat() =0;
};

Human::Human()
{
    cout << "Human::Human()" << endl;
}
Human::~Human()
{
    cout << "Human::~Human()" << endl;
}
Human::Human(int tmp)
{
    cout << "Human::Human(int tmp)" << endl;
}
//Men是Human的子类
class Men:public Human
{
public:
    Men();
    Men(int);
    ~Men();
private:

public:
    virtual void eat();
};

Men::Men()
{
    cout << "Men::Men()" << endl;
}
Men::~Men()
{
    cout << "Men::~Men()" << endl;
}

Men::Men(int tmp)
{
    cout << "Men::Men(int tmp)" << endl;
}
void Men::eat()
{
    cout << "men eat mi" << endl;
}
//Women是Human的子类
class Women :public Human
{
public:
    Women();
    Women(int);
    ~Women();
private:

public:
    virtual void eat();
};
Women::Women()
{
    cout << "Women::Women()" << endl;
}
Women::~Women()
{
    cout << "Women::~Women()" << endl;
}
Women::Women(int tmp)
{
    cout << "Women::Women(int tmp)" << endl;
}
void Women::eat()
{
    cout << "women eat miantiao" << endl;
}
int main()
{
    //引用
    Human* phuman = new Men;
    Human& q = *phuman;
    cout << typeid(*phuman).name() << endl;
    cout << typeid(q).name() << endl;

        //1. typeid判断两个指针指向的是否是同一种类型的对象
        Human* phuman_1 = new Men;
    Human* phuman_2 = new Women;
    //比较对象,看的是new出来的是哪个对象或者该指针指向的是哪个对象,和定义该指针是定义的类型无关;
    //不要忘记*,解引用;
    if (typeid(*phuman_1) == typeid(*phuman_2)) //不成立
        cout << "same!" << endl;
    else
        cout << "not same!" << endl;

    if (typeid(*phuman_1) == typeid(Men))
        cout << "puhuman_1 is Men" << endl;
        //基类必须要有虚函数,否则上述条件不成立;
        //如果基类中不含虚函数,那么typeid返回的是表达式的静态类型;
    return 0;
}

type_info类

typeid就返回一个常量对象的引用,这个常量对象是一个标准库类型type_info(类/类类型)

#include <iostream>
using namespace std;
class Human
{
public:
    Human();
    Human(int);
    virtual ~Human();
public:
    int m_Age;
    char m_Name[100];
public:
    virtual void eat() =0;
};

Human::Human()
{
    cout << "Human::Human()" << endl;
}
Human::~Human()
{
    cout << "Human::~Human()" << endl;
}

Human::Human(int tmp)
{
    cout << "Human::Human(int tmp)" << endl;
}
//Men是Human的子类
class Men:public Human
{
public:
    Men();
    Men(int);
    ~Men();
private:

public:
    virtual void eat();
};

Men::Men()
{
    cout << "Men::Men()" << endl;
}
Men::~Men()
{
    cout << "Men::~Men()" << endl;
}

Men::Men(int tmp)
{
    cout << "Men::Men(int tmp)" << endl;
}
void Men::eat()
{
    cout << "men eat mi" << endl;
}
//Women是Human的子类
class Women :public Human
{
public:
    Women();
    Women(int);
    ~Women();
private:

public:

    virtual void eat();
};

Women::Women()
{
    cout << "Women::Women()" << endl;
}
Women::~Women()
{
    cout << "Women::~Women()" << endl;
}

Women::Women(int tmp)
{
    cout << "Women::Women(int tmp)" << endl;
}
void Women::eat()
{
    cout << "women eat miantiao" << endl;
}
int main()
{
    //name
    Human* phuman = new Men;
    const type_info& tp = typeid(*phuman);
    cout << tp.name() << endl;

    //== !=

    return 0;
}

RTTI与虚函数表

  • C++中,如果类含有虚函数,编译器会对该类产生一个虚函数表;
  • 虚函数表中有很多项,每一项都是一个指针,每个指针指向的是这个类里的各个虚函数的入口地址;
  • 虚函数表项里,第一个表项很特殊,他指向的不是虚函数的入口地址,指向的实际上是咱们这个类所关联的type_info对象;
int main()
{
    Human* phuman = new Men;
    const type_info& tp = typeid(*phuman);
    //phuman对象里有一个指针,指向这个对象所在的类Men里的虚函数表
    return 0;
}

原文链接: https://www.cnblogs.com/NaughtyCoder/p/13343848.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    【C/C++】【类和对象】RTTI和虚函数表

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/368689

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午6:33
下一篇 2023年3月2日 下午6:33

相关推荐