在dynamic binding
中,函数调用根据指针指向的对象类型绑定到函数实现。
假设我们有以下代码:
base *bptr = new derived;
bptr->func();
让函数func
在基类中声明为虚拟。然后,由于动态绑定,将在运行时调用派生类的虚函数func
版本。
我理解上述概念。
但是在研究了上述概念后,我对以下概念感到困惑。
在上面的代码片段中,指向派生类对象的指针被隐式转换为指向基类对象的指针。然后bptr
实际上将指向派生类对象的基类子对象,而不是指向派生类对象。
由于基类指针bptr
指向基类子对象,因此在运行时不应该调用基类的虚函数func
版本吗?
答案 0 :(得分:3)
您似乎错过了动态绑定实际意味着什么。这意味着即使指针(静态地)引用基础子对象,调用也将被分派到整个对象的(动态)类型。
常见的实现是通过虚函数表。基础子对象将存储指向其所属的实际完整类型的虚函数表的指针作为隐藏成员。所有对虚函数的调用(未禁用动态调度)都通过该额外的间接级别进行路由,确保将调用最终的覆盖。
关于如何管理该表和隐藏指针的细节,编译器使用虚函数为每个类型构建e表,并将代码注入到不同的构造函数中以相应地更新指针。因此,在构建基础子对象时,指针引用基本vtable,但在进入派生构造函数之前,注入的代码将更新指针(在基础中)以引用派生的vtable。
答案 1 :(得分:1)
不要对此感到困惑。 “指向派生类对象的指针被隐式转换为指向基类对象的指针” - 这个语句的意义在于假设derived
有一些方法derivedOnly()
,base
中没有。现在,如果您尝试bptr->derivedOnly();
,那么即使您确实引用了derived
的对象,这也会引发错误。
因此,bptr
确实是指向base
的指针。
答案 2 :(得分:0)
在这个例子中:
base *bptr = new derived;
bptr->func();
base
类仅用作接口来了解可以调用哪些方法,因为它指向派生的对象实例。 vtable(http://en.wikipedia.org/wiki/Virtual_method_table)将调用来自derived
类的方法。