【问题标题】:Interview question about virtual functions in C++C++虚函数面试题
【发布时间】:2025-12-23 14:15:06
【问题描述】:

有人问我这个疯狂的问题。 我已经疯了。

可以使用指向派生类对象的基类指针调用基类中声明为虚拟的方法吗?

这可能吗?

【问题讨论】:

  • 您可能想从The Definitive C++ Book Guide and List 获得一本入门书籍。
  • @James:我想他是在问如果pbase* 并指向derived,你是否可以使用p 调用base::foo() 而不是derived::foo()
  • 我会问面试官的。你为什么要这样做,因为你打破了类层次结构的开发者设计的契约。如果最初的开发人员希望您调用基类方法,他会提供一个非虚拟方法来执行该操作。
  • @sbi:我可能是错的,但是调用基类的虚函数实现对我来说似乎并不是那么基本。詹姆斯是对的,当然,我只是说这是 201 级的东西,而不是 101 级的东西。
  • 即使您“按要求”提供了问题,简单的代码 sn-p 也可能有助于澄清所问的内容。

标签: c++ virtual


【解决方案1】:
class B { 
    public: virtual void foo(); 
};

class D: public B { 
    public: virtual void foo() 
    { 
        B::foo();
    }; 
}

B* b = new D;

解决方案:

  1. b->foo();
  2. b->B::foo()

  3. 或者不要在派生类 D 中覆盖/定义 foo() 并调用 b->foo()

  4. B objb = *b; objb.foo() ; // this is object slicing and not (*b).foo() as in one of the previous answers

【讨论】:

    【解决方案2】:
    class B 
    {
    public: 
        virtual void foo();
    };
    
    class D: public B
    {
    public:
        virtual void foo();
    }
    
    B* b = new D;
    

    尝试调用

    (*b).foo()
    

    调用基类 foo 函数

    【讨论】:

    • 你确定这会调用基类 foo 函数吗?你测试了吗?
    • 我的一般假设是 (*b) 最终会有适当的对象,但在编译和运行时我发现情况并非如此。它仍然调用派生函数。这也让我感到困惑, (*b).foo() 和 B b1 = *b; 之间有什么区别? b1.foo()
    【解决方案3】:

    试试:

    class A            { virtual void foo(); }
    class B : public A { virtual void foo(); }
    
    A *b = new B();
    b->A::foo ();
    

    【讨论】:

    • 其实我觉得应该是"A *b = new B()",而不是"B *b = new B()",来跟题。
    【解决方案4】:

    如果您尝试从基类指针调用虚拟方法,可以。

    这就是多态性。

    如果您要问,使用指向派生类的基类指针,您能否调用被派生类覆盖的基类方法?是的,这也可以通过显式限定基类名称来实现:

    basePtr->BaseClass::myMethod();

    【讨论】:

    • 多态是它对派生类方法进行分类的地方,因为该方法在基类中是虚拟的。即使基类方法已被覆盖,实际上通过指向基类的指针调用基类方法也是绕过不同的多态性。
    • 其实恰恰相反。问题是当对象是覆盖方法的派生类型时,要求调用基类的虚方法。
    • Hrm,所写的问题令人困惑。
    • 嗯,我从来不知道这是一个选项(我猜我从来不需要它)。谢谢!
    • 问题不是很清楚,但答案让问题很清楚。
    【解决方案5】:

    如果我理解正确,你有

    class B 
    {
    public: 
        virtual void foo();
    };
    
    class D: public B
    {
    public:
        virtual void foo();
    }
    
    B* b = new D;
    

    问题是,你能打电话给B::foo()。答案是肯定的,使用

    b->B::foo()
    

    【讨论】:

      【解决方案6】:

      是的——您必须指定全名:

      #include <iostream>
      
      struct base { 
          virtual void print() { std::cout << "Base"; }
      };
      
      struct derived : base {
          virtual void print() { std::cout << "Derived"; }
      };
      
      int main() { 
          base *b = new derived;
          b->base::print();
          delete b;
          return 0;
      }
      

      【讨论】:

        【解决方案7】:

        没有。不是以干净的方式。但是,是的。您必须进行一些指针操作,获取指向 vtable 的指针并进行调用。但这并不完全是指向基类的指针,而是一些智能指针操作。另一种方法是在基类上使用范围解析运算符。

        【讨论】:

        • C++ 确实直接支持问题所要求的内容。 base-&gt;base::function() 可以解决问题。这里不需要 vtable hackery。
        • 重新阅读您的帖子。 “范围解析运算符”不是“另一种方法”。这是您应该考虑的唯一方法。
        【解决方案8】:

        你的意思是这样的。 (其中pBase 是指向基址的类型,但指向的对象实际上是派生自BaseDerived 类型。)

        pBase->Base::method();
        

        是的,这是可能的。

        【讨论】: