C/C++常考面试题(2)

C/C++常考面试题(二)

网上看到的面经,说是dynamic_cast的实现,和RTTI的相关,这才发现原来对这个概念这么模糊,所以作了这个总结。

C/C++常考面试题(二)

  1. RTTI(Runtime Type Information, 运行时类型信息)
    • 它提供了运行时确定对象类型的方法。通过运行时类型信息,程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。
    • RTTI提供了以下两个非常有用的操作符:
      • typeid操作符,返回指针和引用所指的实际类型
      • dynamic_cast操作符,将基类类型的指针或引用安全的转换为派生类型的指针或引用
    • 在C++中存在虚函数,也就存在了多态性。对于多态性的对象,在程序编译时可能会出现无法确定对象的类型的情况。当类中含有虚函数时,其基类的指针就可以指向任何派生类的对象,这时就有可能不知道基类指针到底指向哪个对象的情况,类型的确定要在运行时利用运行时类型标识做出。

    • typeid关键字
      • 该关键字的主要作用是让用户知道当前变量是什么类型的。比如使用typeid(a).name()就可以知道变量a的类型,typeid()返回的是一个const type_info&类型的函数,其头文件为 <typeinfo>现对type_info作一个介绍:

        class type_info
        {
        private:
            type_info(const type_info&);
        
            //type_info类的复制构造函数和赋值运算符是私有的。
            type_info& operator=(const type_info&);
        public:
            virtual ~type_info();//析构函数
        
            //在type_info类中重载了==运算符,该运算符可以比较两个对象的类型是否相等。
            bool operator==(const type_info&)const;
        
            //重载的!=运算符,以比较两个对象的类型是否不相等
            bool operator!=(const type_info&)const;
        
            //使用得较多的成员函数name,该函数返回对象的类型的名字。
            //前面使用的typeid(a).name()就调用了该成员函数
            const char* name()const;
            bool before(const type_info&);
        };

        因为type_info的构造函数和赋值运算符都是私有的,所以不允许用户自己创建type_info的对象。唯一要使用type_info的方法就是使用typeid关键字。

    • dynamic_cast操作符
      • 该转换符用于将一个指向派生类的基类指针或引用转换为派生类的指针或引用,注意,dynamic_cast只能用于含有虚函数的类,其表达式为dynamic_cast<类型>(表达式),其中的类型是指要将表达式转换成的目标类型。
      • dynamic_cast不是一个常量时间的操作,为了确定是否能完成强制类型转换,它必须在运行时进行一些转换细节操作。因此在使用dynamic_cast时,应该权衡对性能的影响。
    • RTTI实现
      • 典型的RTTI是通过VTable中放一个额外的指针来实现的。这个指针指向一个描述该特定类型的typeinfo结构(此结构是否与前面的type_info相同,有待商榷)(每个新类只产生一个typeinfo实例),所以typeid()表达式的作用其实很简单,VPtr用来取typeinfo的指针,然后产生一个typeinfo结构的引用,然后调用库中的一个例程来判断原typeinfo是否与目标typeinfo相同,或者是目标typeinfo的派生类。
      • dynamic_cast的实现也是类似的,通过VTable的一个额外指针来实现的。