>
>
>
Тонкость с виртуальными функциями

Андрей Карпов
Статей: 643

Тонкость с виртуальными функциями

Решил записать один момент, связанный с виртуальными функциями, а то боюсь, что потом его забуду и случайно вновь вернусь к этому вопросу :).

В анализаторе Viva64 есть диагностика ошибок, возникающих в 64-битном коде, когда у виртуальных функций изменяется тип аргумента. Подробнее это описано в документации к продукту здесь: V301.

Вот пример кода, где анализатор выдаст эти предупреждения:

class A
{
public:
  virtual int x(unsigned) { return 1; }
  virtual int y(__int64) { return 2; }
};
class B : public A
{
public:
  int x(size_t) { return 3; } //V301
  int y(ptrdiff_t) { return 4; } //V301
};
void Use()
{
  A *p = new B;
  cout <<p->x(1) << " " <<p->y(1) << endl;
  delete p;
}

В 32-битном режиме на печать будет выдано "3 2", а в 64-битном режиме "1 4". Ошибки в данном коде успешно диагностируются анализатором Viva64. Но недавно меня посетила мысль, что необходимо диагностировать не только изменяющиеся аргументы виртуальных функций, но и возвращаемый аргумент. В голове у меня возник следующий пример, который следует диагностировать как ошибочный:

class A
{
public:
  virtual int x() {};
};
class B : public A
{
public:
  ptrdiff_t x() {};
};

К счастью такой вариант в 64-битном режиме просто не скомпилируется и соответственно не возникнет ошибки связанной с изменением поведения кода. Компилятор Visual C++ выдает ошибку:

error C2555: 'B::x': overriding virtual function return type differs and is not covariant from 'A::x' : see declaration of 'A::x'

После проделанного эксперимента, я начал припоминать, что, кажется, уже проделывал подобное исследование. И соответственно диагностика по возвращаемым значениям не требуется. Подумав, я решил сделать эту запись в блог, чтобы через год в третий раз не вернуться к этому вопросу. :)

Рассмотрим последний момент, связанный с диагностикой функций, где отличается как аргумент, так и возвращаемый тип:

class A
{
public:
  virtual int x(int) { return 1; }
};
class B : public A
{
public:
  ptrdiff_t x(ptrdiff_t) { return 2; } //V301
};

Данный код компилируется и содержит ошибку. Анализатор Viva64 корректно разбирается в подобной ситуации и предупреждает, что аргумент изменяет свой тип в 64-битной системе. После исправления этой ошибки, компилятор откажется компилировать код и будет исправлена вторая ошибка - тип возвращаемого аргумента.