5 回答
因为没有这样的成员。virtual
函数从首先声明它们的类开始,一直到所有派生类。他们不会冒泡。当编译器查看时,arr[ i ]->f2()
它会查找arr
其类型的定义。arr
有(静态)类型A
。因此,编译器查找A
's 的定义以获得合适的定义f2
并且没有找到任何。因此诊断。
virtual
函数可以安全地内联。事实上,所有类内定义都被编译器隐式内联。所以,你A::f1
的已经内联了。
您正在尝试调用f2()
,A*
并且A
没有f2()
声明。
virtual
意味着该方法在通过指向基类(包括对象本身的类)的指针调用时,会在运行时根据您调用它的对象的 vptr 表来解析。它不会使该方法在基类中可见。
内联虚函数是非常安全的,但你不一定会得到你期望的性能提升。内联意味着函数代码在调用点由编译器复制粘贴。请参阅有关内联的 C++ 超级常见问题解答以及为什么它是天上掉馅饼
内联是一个编译时概念。在指向基类的指针上调用的虚拟方法调用在运行时解析。
即以下对虚拟函数的调用可以内联:
B myB("The B.");
b.f1(); // not virtual, might be inlined
首先简单:
我也想知道,内联虚函数安全吗?
是的,虚函数可以内联,但保证多态性始终有效。
例如:
B b;
b.f2();
可以在编译时解析,无需使用虚拟表,因为编译器知道对象的类型为B
.
我想知道为什么 _vptr 指向基类的 VTABLE,即使 arr[1] 向上转换为 B。
它没有。它指向 class 的虚拟表B
,但编译器看不到它。虚拟表是一个实现细节。您正在调用 , 上的函数A*
,因此B
' 的方法不可见。在这个简单的例子中,这很容易,但是一般来说,编译器怎么能知道它实际上arr[1]
是一个指向 a 的指针B
呢?这就是多态性的全部意义,你抽象出派生类型。
你可以做的是:
dynamic_cast<B*>(arr[1]) ? (dynamic_cast<B*>(arr[1]))->f2() : (void)0;
这样想吧。在编译时,编译完全忽略了arr[i]
指向的对象的实际类型。该类型仅在运行时才知道。所以当你写这样的东西时:
arr[i]->f2();
编译器不知道要生成什么代码来进行调用。f2是什么?是在 B 中声明的 f2 吗?如果你还有一个名为 C 的 A 的子类,它也有一个名为 f2 的虚函数,而 arr[i] 指向的对象恰好是 C 类型怎么办?我们不知道。
您会立即看到,在这种情况下唯一正常的行为就是产生错误。
arr[1]
是A*
没有名为 的方法的类型f2
。您必须强制arr[1]
转换为B*
,但我认为这不是一个好主意。改为更改您的数据结构。