1
4

5 回答 5

9

因为没有这样的成员。virtual函数从首先声明它们的类开始,一直到所有派生类。他们不会冒泡。当编译器查看时,arr[ i ]->f2()它会查找arr其类型的定义。arr有(静态)类型A。因此,编译器查找A's 的定义以获得合适的定义f2并且没有找到任何。因此诊断。

virtual函数可以安全地内联。事实上,所有类内定义都被编译器隐式内联。所以,你A::f1的已经内联了。

于 2012-06-20T06:33:14.053 回答
3

您正在尝试调用f2(),A*并且A没有f2()声明。

virtual意味着该方法在通过指向基类(包括对象本身的类)的指针调用时,会在运行时根据您调用它的对象的 vptr 表来解析。它不会使该方法在基类中可见。

内联虚函数是非常安全的,但你不一定会得到你期望的性能提升。内联意味着函数代码在调用点由编译器复制粘贴。请参阅有关内联的 C++ 超级常见问题解答以及为什么它是天上掉馅饼

内联是一个编译时概念。在指向基类的指针上调用的虚拟方法调用在运行时解析。

即以下对虚拟函数的调用可以内联:

B myB("The B.");
b.f1(); // not virtual, might be inlined
于 2012-06-20T06:37:10.173 回答
2

首先简单:

我也想知道,内联虚函数安全吗?

是的,虚函数可以内联,但保证多态性始终有效。

例如:

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;
于 2012-06-20T06:32:52.207 回答
1

这样想吧。在编译时,编译完全忽略了arr[i]指向的对象的实际类型。该类型仅在运行时才知道。所以当你写这样的东西时:

arr[i]->f2();

编译器不知道要生成什么代码来进行调用。f2是什么?是在 B 中声明的 f2 吗?如果你还有一个名为 C 的 A 的子类,它也有一个名为 f2 的虚函数,而 arr[i] 指向的对象恰好是 C 类型怎么办?我们不知道。

您会立即看到,在这种情况下唯一正常的行为就是产生错误。

于 2012-06-20T06:40:26.323 回答
0

arr[1]A*没有名为 的方法的类型f2。您必须强制arr[1]转换为B*,但我认为这不是一个好主意。改为更改您的数据结构。

于 2012-06-20T06:34:46.370 回答