"невиртуальный" деструктор порожденного класса
От: DmitryShm Россия  
Дата: 11.02.13 22:25
Оценка: -2
Как сделать так, чтобы код с невиртуальным деструктором в порожденном классе давал ошибку компиляции? Дело в том, что компилятор дает скомпилировать такой код

class A
{
    public:
        virtual ~A() {}
};

class B : public A
{
    public:
        ~B() {}
};


где деструктор класса B также является виртуальным, несмотря на неуказание слова virtual. Как бы задать опции для современных компиляторов (g++ и MSVC++), чтобы такой код компилировался с ошибками, заставляя явно указывать virtual в определении деструкторов порожденных классов.
Re: "невиртуальный" деструктор порожденного класса
От: Vamp Россия  
Дата: 11.02.13 22:28
Оценка: +3
DS>Как бы задать опции для современных компиляторов (g++ и MSVC++), чтобы такой код компилировался с ошибками, заставляя явно указывать virtual в определении деструкторов порожденных классов.
Никак. Поведение, описанное в стандарте — причем, не только для деструкторов, но и для любых виртуальных функций вообще.
Да здравствует мыло душистое и веревка пушистая.
Re: "невиртуальный" деструктор порожденного класса
От: Nikita.Trophimov  
Дата: 12.02.13 03:56
Оценка:
А зачем? Если дело в том, что Вы хотите быть уверенным в наличии виртуального деструктора у базового класса на этапе компиляции, то это можно реализовать и другими способами. Например, при помощи std::has_virtual_destructor и static_assert.
Re: "невиртуальный" деструктор порожденного класса
От: rg45 СССР  
Дата: 12.02.13 06:20
Оценка:
Здравствуйте, DmitryShm, Вы писали:

DS>Как сделать так, чтобы код с невиртуальным деструктором в порожденном классе давал ошибку компиляции? Дело в том, что компилятор дает скомпилировать такой код

  Пример
DS>
DS>class A
DS>{
DS>    public:
DS>        virtual ~A() {}
DS>};

DS>class B : public A
DS>{
DS>    public:
DS>        ~B() {}
DS>};
DS>

DS>где деструктор класса B также является виртуальным, несмотря на неуказание слова virtual. Как бы задать опции для современных компиляторов (g++ и MSVC++), чтобы такой код компилировался с ошибками, заставляя явно указывать virtual в определении деструкторов порожденных классов.

В связи с чем тебе это понадобилось? Какую проблему создает отсутствие слова virtual?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: "невиртуальный" деструктор порожденного класса
От: DmitryShm Россия  
Дата: 12.02.13 07:01
Оценка:
Здравствуйте, rg45, Вы писали:

R>В связи с чем тебе это понадобилось? Какую проблему создает отсутствие слова virtual?


Очевидно, что это проблема, когда читаешь код и думаешь, что функция на самом деле невиртуальная. Когда надо смотреть определение базового класса, что в случае уровней вложенности больше одного ставит задачу шерстить по заголовкам. А если человеку лень шерстить, как бывает в 99% случаях? Он просто подумает, что вызов невиртуальный, ругнется, и будет писать код с учетом этого. А потом ругнется намного сильнее, когда узнает через несколько дней, что есть на самом деле. Я про то, что код должен быть как можно более самодокументированным. И хотел бы пресекать дурной тон написания на уровне компиляции исходников.
Re[3]: "невиртуальный" деструктор порожденного класса
От: rg45 СССР  
Дата: 12.02.13 07:50
Оценка: +3
Здравствуйте, DmitryShm, Вы писали:

DS>Здравствуйте, rg45, Вы писали:


R>>В связи с чем тебе это понадобилось? Какую проблему создает отсутствие слова virtual?


DS>Очевидно, что это проблема, когда читаешь код и думаешь, что функция на самом деле невиртуальная. Когда надо смотреть определение базового класса, что в случае уровней вложенности больше одного ставит задачу шерстить по заголовкам. А если человеку лень шерстить, как бывает в 99% случаях? Он просто подумает, что вызов невиртуальный, ругнется, и будет писать код с учетом этого. А потом ругнется намного сильнее, когда узнает через несколько дней, что есть на самом деле. Я про то, что код должен быть как можно более самодокументированным. И хотел бы пресекать дурной тон написания на уровне компиляции исходников.


Полиморфное поведение закладываются именно в базовом классе. Раз уж тебя интересует возможность виртуального вызова, значит ты намереваешься обращаться к объекту через указатель (или ссылку) на базу, так ведь?. И какой толк от виртуальной функции (в данном случае от деструктора) в производном классе, если в базовом она не является виртуальной? Так что, знания о базовом классе нужны в любом случае.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: "невиртуальный" деструктор порожденного класса
От: DmitryShm Россия  
Дата: 12.02.13 09:01
Оценка:
Здравствуйте, rg45, Вы писали:

R>Полиморфное поведение закладываются именно в базовом классе. Раз уж тебя интересует возможность виртуального вызова, значит ты намереваешься обращаться к объекту через указатель (или ссылку) на базу, так ведь?. И какой толк от виртуальной функции (в данном случае от деструктора) в производном классе, если в базовом она не является виртуальной? Так что, знания о базовом классе нужны в любом случае.


Вопрос в том, насколько глубоко может быть спрятан базовый класс, и увидит ли программист его объявление. Скажем если наследование такое C -> B -> A, и A используется редко, и чаще используется указатель на базовый класс B, то у программиста отнимет больше времени разобраться, что функции у класса B виртуальные, если слова virtual написаны лишь в объявлении класса A. Отсюда и желание подсказывать компилятором добавлять virtual в объявлениях порожденных классов, помогая хорошему стилю написания.

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

Я понимаю хороший стиль как такой, код которого легко читается и в этом коде быстро можно разобраться. Чем быстрее тем лучше. Каждая лишняя потраченная секунда множится на количество людей, а это на количество дней с момента, когда код уже забыт. Вот и считайте. И тут уже дело не в стандартах, как они позволяют писать, а просто в производительности труда. Было бы здорово иметь инструмент, который бы позволял жестко контролировать применяемый стиль программирования. Такие есть на уровне подсвечивания кода, и их применяем каждый день. Но я хотел бы чтобы перед выпуском очередной версии с тегом я мог бы жестко проверять код уже без визуальных средств на сборочной машине без запущенного X-сервера, а, например, на уровне компилятора (как выяснили выше это не получится) или на уровне какой-нибудь утилиты, которую можно внедрить в сборочный скрипт. Желательно чтобы она была кроссплатформенной.
Re: "невиртуальный" деструктор порожденного класса
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 12.02.13 09:22
Оценка: -1
Здравствуйте, DmitryShm, Вы писали:

DS>где деструктор класса B также является виртуальным, несмотря на неуказание слова virtual. Как бы задать опции для современных компиляторов (g++ и MSVC++), чтобы такой код компилировался с ошибками, заставляя явно указывать virtual в определении деструкторов порожденных классов.

Административно это делается через код ревью и введения стандарта написания кода в конторе. Если хочешь, чтобы деструктор всегда был виртуальный, то заставь всех наследоваться от одного базовго класса.
Sic luceat lux!
Re[2]: "невиртуальный" деструктор порожденного класса
От: DmitryShm Россия  
Дата: 12.02.13 10:03
Оценка: -1
Здравствуйте, Kernan, Вы писали:
K>Административно это делается через код ревью и введения стандарта написания кода в конторе. Если хочешь, чтобы деструктор всегда был виртуальный, то заставь всех наследоваться от одного базовго класса.
У нас review есть (пользуемся плагином для Redmine), стандарт понятное дело тоже. Но если что-то можно сделать быстрее через использование утилит, то мы стараемся их применять. Заставлять наследоваться одного класса --- запросто. Только когда уже есть реализации, то никто не будет терять преимущества наследования реализаций и переписывать или рефакторить код, по крайней мере сразу. Так что ситуация с уровнями вложенности наследования больше 1 вполне практическая.
Re[5]: "невиртуальный" деструктор порожденного класса
От: Evgeny.Panasyuk Россия  
Дата: 12.02.13 11:37
Оценка: -1
Здравствуйте, DmitryShm, Вы писали:

R>>Полиморфное поведение закладываются именно в базовом классе. Раз уж тебя интересует возможность виртуального вызова, значит ты намереваешься обращаться к объекту через указатель (или ссылку) на базу, так ведь?. И какой толк от виртуальной функции (в данном случае от деструктора) в производном классе, если в базовом она не является виртуальной? Так что, знания о базовом классе нужны в любом случае.

DS>Вопрос в том, насколько глубоко может быть спрятан базовый класс, и увидит ли программист его объявление. Скажем если наследование такое C -> B -> A, и A используется редко, и чаще используется указатель на базовый класс B, то у программиста отнимет больше времени разобраться, что функции у класса B виртуальные, если слова virtual написаны лишь в объявлении класса A. Отсюда и желание подсказывать компилятором добавлять virtual в объявлениях порожденных классов, помогая хорошему стилю написания.

Rule of Thumb:
Если у тебя есть A <- B <- C, и ты делаешь допустим delete объекта типа C (или других наследников) через указатель на B, то virtual ~B() желательно написать в B, даже если он уже есть в A. В общем случае, зачем полагаться на то что в A, ведь виртуальный деструктор в B тебе нужен независимо от того есть ли он в A или нет.
Другое дело, если ты через B не делаешь delete, то и virtual там писать не нужно, не зависимо от того есть ли оно в A. Как-то так.
Re: "невиртуальный" деструктор порожденного класса
От: PavelCH  
Дата: 12.02.13 12:12
Оценка:
Здравствуйте, DmitryShm, Вы писали:

DS>Как сделать так, чтобы код с невиртуальным деструктором в порожденном классе давал ошибку компиляции? Дело в том, что компилятор дает скомпилировать такой код


Почитал в википедии про С++x11 и нашел там описание ключевого слова override. http://ru.wikipedia.org/wiki/C%2B%2B11. Современные компиляторы еще не поддерживают эту фичу?
Нехай щастить
Re[2]: "невиртуальный" деструктор порожденного класса
От: PavelCH  
Дата: 12.02.13 12:16
Оценка:
Вот http://gcc.gnu.org/gcc-4.8/cxx0x_status.html кстати прочитал что вроде поддерживает gcc
Нехай щастить
Re[2]: "невиртуальный" деструктор порожденного класса
От: Evgeny.Panasyuk Россия  
Дата: 12.02.13 12:17
Оценка:
Здравствуйте, PavelCH, Вы писали:

DS>>Как сделать так, чтобы код с невиртуальным деструктором в порожденном классе давал ошибку компиляции? Дело в том, что компилятор дает скомпилировать такой код

PCH>Почитал в википедии про С++x11 и нашел там описание ключевого слова override. http://ru.wikipedia.org/wiki/C%2B%2B11. Современные компиляторы еще не поддерживают эту фичу?

Поддерживают даже старые, как расширение MSVC2008. Прочитай внимательней вопрос, он не про override — я тоже сначала про override подумал.
Хотя его можно временно использовать если хочется по-быстрому проверить — virtual в базе или нет.
Re: "невиртуальный" деструктор порожденного класса
От: johny5 Новая Зеландия
Дата: 14.02.13 15:31
Оценка:
Здравствуйте, DmitryShm, Вы писали:

DS>Как сделать так, чтобы код с невиртуальным деструктором в порожденном классе давал ошибку компиляции? Дело в том, что компилятор дает скомпилировать такой код


DS>
DS>class A
DS>{
DS>    public:
DS>        virtual ~A() {}
DS>};

DS>class B : public A
DS>{
DS>    public:
DS>        ~B() {}
DS>};
DS>


Придётся писать какой то скрипт, который бы занимался валидацией сорцов автоматически. На уровне только С++ такого сделать нельзя.
Re[2]: "невиртуальный" деструктор порожденного класса
От: rg45 СССР  
Дата: 14.02.13 16:33
Оценка: +2
Здравствуйте, PavelCH, Вы писали:

DS>>Как сделать так, чтобы код с невиртуальным деструктором в порожденном классе давал ошибку компиляции? Дело в том, что компилятор дает скомпилировать такой код


PCH>Почитал в википедии про С++x11 и нашел там описание ключевого слова override. http://ru.wikipedia.org/wiki/C%2B%2B11. Современные компиляторы еще не поддерживают эту фичу?


Очень жаль, что слова override и final сделаны опциональными (для обратной совместимости), польза от них могла бы быть гораздо более ощутимой, будь они обязательными.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: "невиртуальный" деструктор порожденного класса
От: Evgeny.Panasyuk Россия  
Дата: 14.02.13 18:01
Оценка:
Здравствуйте, rg45, Вы писали:

R>Очень жаль, что слова override и final сделаны опциональными (для обратной совместимости), польза от них могла бы быть гораздо более ощутимой, будь они обязательными.


Спорный вопрос.
Например есть A<-B. Где-то есть удаление B через указатель на A. У A виртуальный деструктор.
Если бы override не был опциональным, то он должен стоять у деструктора B.
Допустим все места где B удаляется через A убрали, и убрали виртуальный деструктор — теперь нужно убирать override у B (и у всех остальных дочерних классов).
Re[3]: "невиртуальный" деструктор порожденного класса
От: Erop Россия  
Дата: 14.02.13 20:43
Оценка:
Здравствуйте, rg45, Вы писали:

R>Очень жаль, что слова override и final сделаны опциональными (для обратной совместимости), польза от них могла бы быть гораздо более ощутимой, будь они обязательными.


Можно предложить коммететчикам завести что-то вроде explicit virtual, который будет требовать явного указания при перекрытии, например...

IMHO, правда, это всё мало поможет против проблем с виртуальными функциями в С++...

Главная проблема тут в том, что когда мы меняем что-то в базе, хорошо бы сделать так, что бы во всех наследниках надо было бы проверить, что всё ещё актуально...

Можно, конечно, как-то ввести версионность. Скажем после слова virtual в угловых скобках писать уникальный ID, и требовать того же писать после override и final + добавить слово для случая "наследуем реализацию из базы".
Но С++ и так на ребус похож, к чему усугублять?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: "невиртуальный" деструктор порожденного класса
От: rg45 СССР  
Дата: 15.02.13 07:41
Оценка: +1
Здравствуйте, Evgeny.Panasyuk, Вы писали:

R>>Очень жаль, что слова override и final сделаны опциональными (для обратной совместимости), польза от них могла бы быть гораздо более ощутимой, будь они обязательными.


EP>Спорный вопрос.

EP>Например есть A<-B. Где-то есть удаление B через указатель на A. У A виртуальный деструктор.
EP>Если бы override не был опциональным, то он должен стоять у деструктора B.
EP>Допустим все места где B удаляется через A убрали, и убрали виртуальный деструктор — теперь нужно убирать override у B (и у всех остальных дочерних классов).

И очень хорошо, что нужно. Это дает нам возможность, глядя только лишь на определение класса B, не заглядывая в A, сделать вывод о том, можно ли удалять объекты класса B по указателю на базу. В этом же и профит, собственно.

А вообще, снятие виртуальности с деструктора "боевого" базового класса — это не заурядный повседневный рефакторинг, тут и надо быть готовым к другим переменам в коде.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[5]: "невиртуальный" деструктор порожденного класса
От: Erop Россия  
Дата: 15.02.13 08:56
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>И очень хорошо, что нужно. Это дает нам возможность, глядя только лишь на определение класса B, не заглядывая в A, сделать вывод о том, можно ли удалять объекты класса B по указателю на базу. В этом же и профит, собственно.


В общем случае всё равно нельзя. Например деструктор базы вообще может быть защищённым...

R>А вообще, снятие виртуальности с деструктора "боевого" базового класса — это не заурядный повседневный рефакторинг, тут и надо быть готовым к другим переменам в коде.


Это да. Это, IMHO, вообще довольно умозрительная ситуация. Типа по соображениям эффективности где-то динамический полиморфизм на статический меняют? так тут да, одними виртуальными деструкторами не отмахаешься
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: "невиртуальный" деструктор порожденного класса
От: Evgeny.Panasyuk Россия  
Дата: 15.02.13 09:28
Оценка: 2 (2)
Здравствуйте, rg45, Вы писали:

R>>>Очень жаль, что слова override и final сделаны опциональными (для обратной совместимости), польза от них могла бы быть гораздо более ощутимой, будь они обязательными.

EP>>Спорный вопрос.
EP>>Например есть A<-B. Где-то есть удаление B через указатель на A. У A виртуальный деструктор.
EP>>Если бы override не был опциональным, то он должен стоять у деструктора B.
EP>>Допустим все места где B удаляется через A убрали, и убрали виртуальный деструктор — теперь нужно убирать override у B (и у всех остальных дочерних классов).
R>И очень хорошо, что нужно. Это дает нам возможность, глядя только лишь на определение класса B, не заглядывая в A, сделать вывод о том, можно ли удалять объекты класса B по указателю на базу. В этом же и профит, собственно.

Если объект удаляется через указатель на B, то почему бы не добавить вручную опциональный future-proof virtual/override. Если же он не удаляется через B то ничего хорошего в non-optional virtual/override не вижу.
Да, и эти non-optional virtual/override ограничивают гибкость кода.
Например:
struct Static
{
};
struct Polymorphic
{
    virtual ~Polymorphic(){}
};

template<class Policy>
struct Derived: Policy
{
    /* non-optional virtual? */ ~Derived() /* non-optional override? */
    {
    }
};

int main()
{
    Derived<Polymorphic> p;
    Derived<Static> s;
}



R>А вообще, снятие виртуальности с деструктора "боевого" базового класса — это не заурядный повседневный рефакторинг, тут и надо быть готовым к другим переменам в коде.


Не обязательно снятие "virtual" с деструктора базы. Достаточно убрать эту базу из родителей.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.