MST

星途 面试题库

面试题:C++ 虚函数表指针在对象中的位置及原理

在C++中,包含虚函数的类对象内部有一个虚函数表指针。请阐述虚函数表指针通常在对象中的什么位置,以及它是如何与虚函数表进行关联的?同时,解释当一个类从含有虚函数的基类派生时,虚函数表指针和虚函数表会发生怎样的变化?
28.8万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 虚函数表指针的位置
    • 在C++中,虚函数表指针(vptr)通常位于对象的起始位置。这是因为编译器在处理含有虚函数的类时,会将vptr作为对象的第一个成员来布局,这样可以高效地通过对象地址直接访问到vptr。例如,对于如下类定义:
    class Base {
    public:
        virtual void func() {}
    };
    
    当创建Base类的对象Base obj;时,obj的内存布局中,最开始的位置存放的就是vptr。
  2. 虚函数表指针与虚函数表的关联
    • 虚函数表指针(vptr)指向一个虚函数表(vtbl)。虚函数表是一个函数指针数组,每个数组元素是一个指向虚函数的指针。当对象调用虚函数时,首先通过对象的vptr找到对应的虚函数表,然后根据虚函数在虚函数表中的索引来调用相应的虚函数。例如,假设Base类有两个虚函数func1func2,虚函数表中会有两个函数指针,分别指向Base::func1Base::func2。当Base类对象调用func1时,通过vptr找到虚函数表,再从虚函数表的对应位置取出Base::func1的函数指针并调用。
  3. 派生类中虚函数表指针和虚函数表的变化
    • 虚函数表指针:派生类对象同样会继承基类的虚函数表指针。如果派生类没有定义自己的虚函数,派生类对象的vptr指向基类的虚函数表。例如:
    class Derived : public Base {
    };
    
    Derived类对象的vptr与Base类对象的vptr指向相同的虚函数表(如果Derived没有重写虚函数)。
    • 虚函数表
      • 重写虚函数的情况:当派生类重写了基类的虚函数时,派生类的虚函数表中对应虚函数的位置会替换为派生类重写后的虚函数指针。例如:
      class Base {
      public:
          virtual void func() { std::cout << "Base::func" << std::endl; }
      };
      class Derived : public Base {
      public:
          void func() override { std::cout << "Derived::func" << std::endl; }
      };
      
      Derived类的虚函数表中,func函数对应的指针指向Derived::func,而不是Base::func
      • 新增虚函数的情况:如果派生类新增了自己的虚函数,这些新增的虚函数会追加到虚函数表的末尾。例如:
      class Base {
      public:
          virtual void func() { std::cout << "Base::func" << std::endl; }
      };
      class Derived : public Base {
      public:
          void func() override { std::cout << "Derived::func" << std::endl; }
          virtual void newFunc() { std::cout << "Derived::newFunc" << std::endl; }
      };
      
      Derived类的虚函数表中,先有Derived::func(重写基类的虚函数),然后在末尾追加Derived::newFunc的函数指针。