struct A {
int a;
virtual void print() {}
};
struct B : A {
int b;
virtual void print() {}
};
int main(void)
{
A *a = new B;
a[0].print(); // g++, vs2010, clang call B::print.
}
所有三个 g++、vs2010、clang 都调用 B::print。几乎怀疑我的 C++ 101。我的印象是,对对象使用点不会导致动态调度。只有 -> 带有指针和带有引用的点才会导致动态调度。
所以我的问题是这段代码是否可移植?
a[0]
与 *a
相同,该表达式是 A
的 reference,虚拟调度通过引用发生,就像通过指针一样。
a->print()
和 (*a).print()
完全相同。
它是便携式的。 a[0] 返回一个引用,引用也使用动态调度。
是的。相当于-
a->print();
它是可移植的并且行为是明确定义的。指针上的
operator[]
只是进行指针算术和取消引用。它将 0 * sizeof(A)
添加到指针,因此从某种意义上说,它是一个“危险”操作,因为除了 0 之外的任何其他值都会失败(在 B 数组上),但因为 0 * sizeof(A) 是 0,在此如果你没问题,因为它加了 0。
多态性适用于引用和指针。
将
a[0]
与指针一起使用是明确定义的,并且含义与 *(a + 0)
相同。这就是内置 []
运算符的工作原理。
关于编译器在没有多态性时不需要使用动态分派,您的说法部分正确。但这只是一种常见的优化,并不是语言所必需的。 当代码为
A a;
a.print();
编译器可以直接调用正确的函数,因为它可以在编译时告诉对象类型。