在派生对象上调用基函数
calling a base function on a derived object
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()
函数在派生 class 的对象上调用时调用 derived::foo
函数,即使该函数本身仅存在于基础 class.[=13= 中]
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;;
}
};
(请注意,在您的示例中所有方法都是私有的,我想那只是一个错字)
当派生 class 中的成员函数重写 基 class 中的虚拟成员函数时,这意味着它完全替换了函数大多数目的的定义。因此,在 main
中创建的对象 der
上调用函数 foo
通常会使用 Derived::foo
定义。无论调用 foo
的代码是在 Derived
的成员中还是在 Base
的成员中,或者两者都不在 class.
中,此行为是一致的
两个主要的例外是:
- 如果您使用“qualified-id”
class_type::func_name
语法来调用该函数,将禁用虚函数逻辑并仅调用您命名的函数(在正常名称查找和重载解析之后)。
既然你说你想让程序调用 base::foo
,那么把 base::bar
改成:
void bar() {
base::foo();
std::cout << "base::bar was called" << std::endl;
}
- 在基类 class 的构造函数或析构函数期间,将调用基类 class(或其基类之一)中的函数,忽略派生 class 中的覆盖程序(西)。该对象被认为还不是或不再是派生类型的对象。 (如果派生函数被调用并使用任何尚未创建或已经销毁的派生成员,这将是麻烦。)
当您声明一个函数 virtual
时,编译器将为每个创建的对象生成一个 vtable
,在您的情况下,由于该对象是一个 derived
函数 [=对于该实例,11=] 将始终指向 derived::foo()
。
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()
函数在派生 class 的对象上调用时调用 derived::foo
函数,即使该函数本身仅存在于基础 class.[=13= 中]
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;;
}
};
(请注意,在您的示例中所有方法都是私有的,我想那只是一个错字)
当派生 class 中的成员函数重写 基 class 中的虚拟成员函数时,这意味着它完全替换了函数大多数目的的定义。因此,在 main
中创建的对象 der
上调用函数 foo
通常会使用 Derived::foo
定义。无论调用 foo
的代码是在 Derived
的成员中还是在 Base
的成员中,或者两者都不在 class.
两个主要的例外是:
- 如果您使用“qualified-id”
class_type::func_name
语法来调用该函数,将禁用虚函数逻辑并仅调用您命名的函数(在正常名称查找和重载解析之后)。
既然你说你想让程序调用 base::foo
,那么把 base::bar
改成:
void bar() {
base::foo();
std::cout << "base::bar was called" << std::endl;
}
- 在基类 class 的构造函数或析构函数期间,将调用基类 class(或其基类之一)中的函数,忽略派生 class 中的覆盖程序(西)。该对象被认为还不是或不再是派生类型的对象。 (如果派生函数被调用并使用任何尚未创建或已经销毁的派生成员,这将是麻烦。)
当您声明一个函数 virtual
时,编译器将为每个创建的对象生成一个 vtable
,在您的情况下,由于该对象是一个 derived
函数 [=对于该实例,11=] 将始终指向 derived::foo()
。