如何在内部(在运行时)决定调用哪个函数,基类或派生类函数。在下面的示例代码中,如何决定调用 B 的 fn()和 A 的 fn2()
Class A {
virtual void fn() { std::cout << "A" < <std::endl; }
virtual void fn2() { std::cout << "A-fn2" < <std::endl; }
};
Class B : A
{
void fn() { std::cout << "B" < <std::endl; }
}
int main() {
B b = new B;
A *a = &b;
a->fn();
a->fn2();
}
输出 B 和 A-fn2()
基本上如何在运行时决定是调用派生类函数还是基类函数?
答案 0 :(得分:1)
在纠正编译错误后,您的问题的答案是输出将是:
A A-fn2 。
您的代码中不存在virtual
函数,需要进行任何运行时决策。编译器本身将评估函数的调用。
假设您创建A
方法virtual
,那么在运行时进行的函数调用决策是基于引用哪个对象。
答案 1 :(得分:1)
您所拥有的被称为动态/运行时多态
规则是:
在运行时调用要在运行时调用的方法,具体取决于指针指向的实际对象。
编译器如何执行此操作完全取决于实现。通常,您的代码应该只依赖于行为而不是内部因素。但是,所有已知的编译器都通过虚拟表(vtbl
)&amp;虚拟指针(vptr
)机制。
如何实现运行时多态?
一个类有一个virtual
方法,该类被称为多态类,编译器为该类创建vtbl
。 vtbl
存储该类中所有虚拟方法的地址。编译器还为该类的每个对象添加一个特殊指针vptr
。 vptr
点(存储地址)vtbl
一旦类派生自这样的多态类,编译器将派生类的vtbl
中的方法的地址替换为派生类中的覆盖函数的地址。对于非覆盖方法,地址仍然是基类方法。
因此,每个类通常有一个vtbl
,而每个对象实例都有一个vptr
,它指向vtbl
。每个类的vtbl
存储其自己的虚拟方法的地址。
在运行时,vptr
指针内的this
被取出,并进一步获取vtbl
中的相应方法地址&amp;然后它被调用,这种机制称为动态调度
因此,由于该机制,可以根据指针所指向的对象的类型来确定要调用的适当方法。
这个C ++ - Faq是一个很好的进一步阅读:
的 Inheritance — virtual functions 强>