【问题标题】:calling a base function on a derived object在派生对象上调用基函数
【发布时间】:2021-05-18 11:31:44
【问题描述】:
class base{
   public:
   virtual void foo(){
     std::cout << "base::foo was called" << std::endl;;
   }
 
   void bar(){
     foo();
     std::cout << "base::bar was called" << std::endl;;
   }
};

class derived : public base {
  public:
  void foo() {
    std::cout << "derived::foo was called" << std::endl;
  }
};

int main() {
    derived der;
    der.bar();
    // desired output = "base::foo was called" "base::bar was called"
    // actual output = "derived::foo was called" "base::bar was called"

}

我在这里遗漏了什么明显的东西吗?
为什么bar()函数在派生类的对象上调用时调用derived::foo函数,即使函数本身只存在于基类中。

【问题讨论】:

标签: c++ inheritance virtual


【解决方案1】:

base::foo 被声明为virtual,因此使用虚拟调度。如果您不希望这样,请明确致电base::foo

struct  base{
   virtual void foo(){
     std::cout << "base::foo was called" << std::endl;;
   }
 
   void bar(){
     base::foo();
     std::cout << "base::bar was called" << std::endl;;
   }
};

(请注意,在您的示例中所有方法都是私有的,我想这只是一个错字)

【讨论】:

  • 是的,这些功能是公开的,我在我的代码示例中修复了它。感谢您的回答!
  • 您实际上并没有回答实际问题,“为什么”。简单的答案是它的定义方式,这使得 virtual 函数很有用。
【解决方案2】:

当派生类中的成员函数覆盖基类中的虚成员函数时,这意味着它在大多数情况下完全替换了函数定义。所以在main 中创建的对象der 上调用函数foo 通常会使用Derived::foo 定义。无论调用 foo 的代码是在 Derived 的成员中,还是在 Base 的成员中,或者两者都不是类,这种行为都是一致的。

两个主要的例外是:

  1. 如果您使用“qualified-id”class_type::func_name 语法调用该函数,则会禁用虚函数逻辑并仅调用您命名的函数(在正常名称查找和重载解析之后)。

既然你说你想让程序调用base::foo,就把base::bar改成这样:

void bar() {
    base::foo();
    std::cout << "base::bar was called" << std::endl;
}
  1. 在基类的构造函数或析构函数期间,将调用基类(或其基类之一)中的函数,忽略派生类中的覆盖器。该对象被认为还不是或不再是派生类型的对象。 (如果调用了派生函数并使用了任何尚未创建或已销毁的派生成员,这将很麻烦。)

【讨论】:

    【解决方案3】:

    当您声明函数virtual 时,编译器将为创建的每个对象生成vtable,在您的情况下,由于对象是derived,因此函数vtable 将始终指向derived::foo()对于那个例子。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-01
      相关资源
      最近更新 更多