对于虚函数,当声明虚拟时以及何时不访问某些方法时会发生什么。
我的想法:
如果它是虚拟的,则调用实例将在其虚函数表中搜索该函数,如果它是指向派生实例的基本实例指针,则将调用派生实例的虚函数实现。如果它不是虚函数,则调用调用实例的函数调用。
对吗?
答案 0 :(得分:1)
从语言标准的角度来看,没有什么比你可能已经知道的更多:如果一个函数是虚函数,那么在任何基类引用或指针上调用它将导致调用最派生的实际函数。
就是这样。重要的是行为。
你真正想要的是编译器如何实现这一点。实际上,vtable是实现虚拟调度的最流行方式。它本质上是一个函数指针列表,它为每个具有虚函数的类维护。 (请记住,从具有虚函数的类派生会自动使这些函数在派生类中再次变为虚拟。)
但是,编译器实际调用函数的方式各不相同。
如果函数不是虚函数,则在编译时已知,并静态调度到调用它的静态类类型的成员函数。
如果函数是虚函数但编译器可以在编译时证明基本引用/指针的动态类型,它可以选择直接调用相应派生类的函数。
如果编译器无法推断出动态类型,则函数调度会在运行时通过查找vtable中实际(派生的)函数的函数指针来发生。
示例:
struct A {
void foo();
virtual void bar();
};
struct B : A {
void foo(); // hides A::foo() -- very bad style
void bar(); // automatically virtual!!
};
int main() {
B x;
A * a1 = &x; // pointer-to-base;
A * a2 = get_pointer();
a1->foo(); // static dispatch to A::foo() (non-virtual function)
a1->bar(); // dispatch to B::foo(), possibly resolved statically
a2->bar(); // dynamically dispatched to whatever the most derived class is
}
答案 1 :(得分:0)
右。如果通过基类指针调用virtual
函数,则将调用覆盖。另一方面,如果通过基类指针调用非virtual
函数,则将调用基类函数。
通过引用而不是指针调用时也是如此。
处理基类指针时要注意的一件事是slicing。如果你这样做:
Base* pb = new Der;
Base other = *pb;
other
切割了对象,所有Der
都消失了。