Почему предупреждение C4265 Visual C++ (виртуальная функция-член и отсутствие виртуального деструктора) отключено по умолчанию?

Visual C++ может выдавать предупреждение C4265, когда класс имеет по крайней мере одну виртуальную функцию-член и не имеет виртуального деструктора.

Очевидно, предупреждение предназначено для обнаружения случаев, когда объект производного класса является deleted через указатель на базовый класс, а в базовом классе нет виртуального деструктора. Такая ситуация приводит к неопределенному поведению. Кстати, я только что нашел пример этой ситуации в довольно большой кодовой базе, включив C4265 в Visual C++.

И это предупреждение отключено по умолчанию.

Почему? Что произойдет, если я включу его и добавлю виртуальный деструктор к каждому классу, где выдается предупреждение?


person sharptooth    schedule 08.11.2011    source источник


Ответы (4)


В ссылке документации по это предупреждение объясняет рассуждения Microsoft. If a warning is off by default, most users would not want to see it.

person Hans Olsson    schedule 08.11.2011

Я предполагаю, что иногда вам не нужен виртуальный деструктор, даже если у вас есть виртуальные функции (и поэтому подумайте о наследовании от него).

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

Виртуальный деструктор также означает, что вы должны реализовать конструктор копирования и оператор присваивания (правило трех), которые также не нужны, если ваши члены класса являются просто типами POD.

Итак, подведем итог: вы получите это предупреждение даже для классов, где вам не нужен виртуальный деструктор, так зачем он?

person Luchian Grigore    schedule 08.11.2011
comment
Я не думаю, что правило трех работает таким образом. Для полиморфного удаления достаточно пустого виртуального деструктора. Это тот самый деструктор, который у вас уже есть (предоставленный компилятором), просто virtual. - person K-ballo; 08.11.2011

Я думаю, много предупреждений может быть среди тех, кто использует классы шаблона Mixin.

WikiPedia: В объектно-ориентированных языках программирования миксин — это класс, который предоставляет определенную функциональность для наследования или повторного использования подклассом, но не предназначен для инстанцирования (генерации объектов этого класса). Миксины являются синонимами абстрактных базовых классов. Наследование от примеси — это не форма специализации, а скорее средство сбора функциональности. Класс или объект может «наследовать» большую часть или всю свою функциональность от одного или нескольких примесей, поэтому примеси можно рассматривать как механизм множественного наследования.

Пример:

Смешанный класс

template <typename T> struct AddNoEq {
  virtual bool operator==(const T &cmp) const = 0;
  bool operator!=(const T &cmp) const {
    return !static_cast<const T*>(this)->operator== (cmp);
  }
};

Использовать:

struct Complex : public AddNoEq<Complex> {
  Complex(int re, int im): re_(re), im_(im) { }

  virtual bool operator==(const Complex& cmp) const {
      return cmp.re_ == this->re_ && cmp.im_ == this->im_;
  }
  // ...
private:
  int re_, im_;
};

int main()
{
  Complex a(1, 2), b(2, 3);

    if (a != b)
      std::cout << "OK!" << std::endl;

    return 0;
}
person Community    schedule 21.01.2012

Microsoft иногда предупреждает об «устаревших функциях», которые не помечены как таковые комитетом по спецификациям, или об определенных «хороших или плохих практиках».

Наличие невиртуального деструктора в объекте, который имеет виртуальные методы, представляет собой потенциальный риск, если этот объект предназначен для использования в полиморфной среде ООП (где delete pObject должен правильно также delete pDerived, даже если он просматривается с помощью pObject). Но это всего лишь одна из парадигм поддержки С++... поэтому такое предупреждение может быть бессмысленным:

Также p->dosomething() не вызывает Derived::dosomething, если dosomething не является виртуальным, но для этого не генерируется предупреждение.

Для меня, delete p, попытка P::~P() привести к вызову D::~D() не является особым случаем и не должна заслуживать предупреждения.

Но, к сожалению, ООП была первой парадигмой, которую С++ изначально поддерживал, и парадигмой, на которую ссылается большинство программистов, распространяемых книг и учителей, поэтому они развернули передовую практику «не выводить, если деструктор не виртуальный», к сожалению, сообщается также Скоттом Мейерсом в его «Эффективном C ++», что сделало его «популярным» и на него постоянно ссылаются, даже если нет технических причин для его дальнейшего существования.

Сегодня это бессмысленно, как и большинство фраз «не делай этого, не делай того» (включая знаменитое «перейти к вредным действиям» Дейкстры, которое сделало много нового акцента на структурном программировании, но также и множество нелепых способов крутитесь вокруг, чтобы избежать этого. Ха ... Miscrosoft еще не предупредил об использовании goto ... Может быть, Мейерс более влиятельный, чем Джикстра??)

Единственная хорошая практика — «НИЧЕГО не делай, если не знаешь, что делаешь!». Ничто не запрещает принять предложение, но "лучшая практика" - это не "всегда хорошая практика" (иначе она не будет "лучшей": будет просто "только") и компилятор (как формальный инструмент) не должен предупреждать о субъективных чувства.

person Emilio Garavaglia    schedule 08.11.2011