Является ли этот код C ++ переносимым? - PullRequest
2 голосов
/ 12 января 2012
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, лязг вызова B :: print.Почти сомневаюсь в моем C ++ 101. У меня сложилось впечатление, что использование точки с объектом не приводит к динамической диспетчеризации.Только -> с указателем и точкой со ссылкой приведет к динамической диспетчеризации.

Итак, мой вопрос, переносим ли этот код?

Ответы [ 5 ]

14 голосов
/ 12 января 2012

a[0] совпадает с *a, и это выражение является ссылкой на A, и виртуальная диспетчеризация происходит по ссылкам так же, как и через указатели.a->print() и (*a).print() полностью идентичны.

4 голосов
/ 12 января 2012

Это портативный. [0] возвращает ссылку, и ссылки также используют динамическую диспетчеризацию.

3 голосов
/ 12 января 2012

Да.Это эквивалентно -

a->print();
1 голос
/ 12 января 2012

Использование a[0] с указателем хорошо определено и означает то же самое, что и *(a + 0).Вот как работает встроенный оператор [].

Вы частично правы в том, что компилятору не требуется для использования динамической диспетчеризации, когда нет полиморфизма.Это просто обычная оптимизация, и она не требуется языком.

Когда код

A a;
a.print();

, компилятор может напрямую вызывать правильную функцию, потому что он может указать тип объектаво время компиляции.

1 голос
/ 12 января 2012

Это портативно, и поведение четко определено. operator[] для указателя просто делает арифметику указателя и разыменование. Он добавляет 0 * sizeof(A) к указателю, так что в некотором смысле это «опасная» операция, как и любое другое значение, но 0 будет неудачным (для массива B), но так как 0 * sizeof (A) равно 0, в этом если все в порядке, потому что он добавляет 0.

Полиморфизм работает как с ссылками, так и с указателями.

...