在派生对象上调用基函数


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函数,即使该函数本身只存在于基类中

当派生类中的成员函数像这样覆盖基类中的虚成员函数时,这意味着它在大多数情况下完全取代了函数定义。因此,在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. 在基类的构造函数或析构函数期间,将调用基类(或其基类之一)中的函数,忽略派生类中的重写。该对象被认为还不是或不再是派生类型的对象。(如果调用派生函数并使用任何尚未创建或已经销毁的派生成员,这将是麻烦的。)

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时,编译器将为创建的每个对象生成一个vtable,在您的例子中,由于对象是derived,因此函数vtable将始终指向该实例的derived::foo()

最新更新