Наследование от классов без виртуального деструктора?
От: Андрей Тарасевич Беларусь  
Дата: 24.10.03 23:20
Оценка: 108 (15) +4
#Имя: FAQ.cpp.virtualdtor2
Здравствуйте, Bell, Вы писали:

B>В данном да. Но ИМХО всегда следует придеживаться определенных правил. При программировании на С++ самодисциплина играет далеко не самую последнюю роль.


Правило "Не делать наследования от классов без виртуального деструктора" является одним из тех ложных правил, которые были популярны среди С++ программистов среднего примерно пару лет назад. Это правило успешно умерло, как и другие ложные правила типа "Каждая функция должна иметь только одну точку выхода" и т.п. Точнее, это правило не сколько умерло, сколько наконец отодвинулось на свое правильное место — в узкую область классического ООП программирования на С++ с применением динамического полиморфизма.

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

Мне странно видеть, что это ложное правило еще живет в этой конференции. Наследовать от стандартных контейнеров можно и нужно, в тех ситуациях, когда это оправданно. Наличие или отсутсвие виртуального деструтора при этом никакой роли не играет. Виртуальный деструктор — атрибут полиморфного класса. Здесь же никто не пытается создать полиморфный класс.

ЗХ>>фраза "Контейнеры STL не предназначены для наследования" означает. что у них нет виртуальных методов, которые можно было бы переопределить в наследнике.

B>В том числе у них нет виртуального деструктора.

Это соврешнно не важно. Это означает, только то, что такие объекты не являются полиморфно-удаляемыми и не более. Тем не менее это не повод отказываться от наследования, если это действительно необходимо. В generic programming наследование применяется для достижения подобных целей повсеместно. Задаваться при этом вопросом о каком-то виртуальном деструкторе, мягко говоря, неуместно.

ЗХ>>...а для расширения функциональности паблик-наследование самое оно.

B>Спорное утверждение, ну да ладно...

Это утверждение перестало быть спорным довольно давно. Строго говоря, такое применение публичного наследования упоминает еще Страуструп в D&E. Александреску в "Modern C++ Design" использует публичное наследование для подобных целей приктически повсеместно.

ЗХ>>...либо делать обертки ко всем его операциям.

B>Да, интерфейс придется повторить. Это так ужасно?

Это соврешенно неприемлемо. Да и зачем, если есть публичное наследование?
Best regards,
Андрей Тарасевич
Re[5]: vector<int> = int
От: Bell Россия  
Дата: 24.10.03 10:16
Оценка: 18 (1) -1
Здравствуйте, Зверёк Харьковский, Вы писали:

B>>Контейнеры STL не предназначены для наследования. Лучше используй включение.


ЗХ>ну, это, ИМХО, для данного случая по-барабану

В данном да. Но ИМХО всегда следует придеживаться определенных правил. При программировании на С++ самодисциплина играет далеко не самую последнюю роль.

ЗХ>фраза "Контейнеры STL не предназначены для наследования" означает. что у них нет виртуальных методов, которые можно было бы переопределить в наследнике.

В том числе у них нет виртуального деструктора.

ЗХ>...а для расширения функциональности паблик-наследование самое оно.

Спорное утверждение, ну да ладно...

ЗХ>...а при включении пришлось бы либо делать включенный контейнер паблик-членом. что не есть гут,

А это еще зачем?!

ЗХ>...либо делать обертки ко всем его операциям.

Да, интерфейс придется повторить. Это так ужасно?
Любите книгу — источник знаний (с) М.Горький
Re[4]: vector<int> = int
От: Зверёк Харьковский  
Дата: 24.10.03 09:55
Оценка: 18 (1)
Здравствуйте, Bell, Вы писали:

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



B>Контейнеры STL не предназначены для наследования. Лучше используй включение.


ну, это, ИМХО, для данного случая по-барабану

фраза "Контейнеры STL не предназначены для наследования" означает. что у них нет виртуальных методов, которые можно было бы переопределить в наследнике. а для расширения функциональности паблик-наследование самое оно. а при включении пришлось бы либо делать включенный контейнер паблик-членом. что не есть гут, либо делать обертки ко всем его операциям.
FAQ — це мiй ай-кью!
Re[7]: vector<int> = int
От: Павел Кузнецов  
Дата: 25.10.03 14:49
Оценка: 6 (1)
Здравствуйте, Андрей, Вы писали:

ЗХ>>> фраза "Контейнеры STL не предназначены для наследования" означает. что у них нет

ЗХ>>> виртуальных методов, которые можно было бы переопределить в наследнике.

B>> В том числе у них нет виртуального деструктора.


AT> соврешнно не важно. Это означает, только то, что такие объекты не являются

AT> полиморфно-удаляемыми и не более.

Невиртуальность членов std::vector, помимо того, что, в частности, объекты унаследованного
класса (VectorEx) не являются полиморфно-удаляемыми, в общем, приводит еще и к тому, что
инварианты VectorEx могут нарушаться, если где-нибудь есть модификация объектов VectorEx
через ссылки/указатели на std::vector.

B>> Да, интерфейс придется повторить. Это так ужасно?


АТ> Это соврешенно неприемлемо. Да и зачем, если есть публичное наследование?


Еще лучшим вариантом, вероятно, было бы наличие какого-нибудь встроенного механизма,
позволяющего получить в VectorEx тот же интерфейс, что и в std::vector, но не позволять,
по крайней мере, неявное приведение VectorEx* -> std::vector*.

P.S. естественно, если инварианты VectorEx тождественны инвариантам std::vector,
упомянутых проблемы не имеют никакого значения.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
vector<int> = int
От: Tan4ik Россия  
Дата: 24.10.03 08:01
Оценка:
Возможно ли такое?

typedef vector<int> mytype;

mytype& operator=(mytype& a; int b)
{
  a.clear();
  a.push_back(b);
  return a;
}

int main()
{
  mytype a = 2;
  assert(a.size() == 1);
  assert(a[0] == 2);
  return 0;
}


Код конечно не компилируется.
---
С уважением,
Лазарев Андрей
Re: vector<int> = int
От: Bell Россия  
Дата: 24.10.03 08:10
Оценка:
Здравствуйте, Tan4ik, Вы писали:

T>Возможно ли такое?


T>
T>typedef vector<int> mytype;

T>mytype& operator=(mytype& a; int b)//Может запятая?
T>{
T>  a.clear();
T>  a.push_back(b);
T>  return a;
T>}

T>int main()
T>{
T>  mytype a = 2;//Конструктор копии, но никак не operator =()
T>  assert(a.size() == 1);
T>  assert(a[0] == 2);
T>  return 0;
T>}
T>


T>Код конечно не компилируется.

Ничего удивительного.
Любите книгу — источник знаний (с) М.Горький
Re: vector<int> = int
От: Зверёк Харьковский  
Дата: 24.10.03 08:13
Оценка:
Здравствуйте, Tan4ik, Вы писали:

T>Возможно ли такое?


T>
T>typedef vector<int> mytype;

T>mytype& operator=(mytype& a; int b)
T>{
T>  a.clear();
T>  a.push_back(b);
T>  return a;
T>}

T>int main()
T>{
T>  mytype a = 2;
T>  assert(a.size() == 1);
T>  assert(a[0] == 2);
T>  return 0;
T>}
T>


T>Код конечно не компилируется.


угу. operator= обязан быть мембером
FAQ — це мiй ай-кью!
Re[2]: vector<int> = int
От: Bell Россия  
Дата: 24.10.03 08:14
Оценка:
Здравствуйте, Bell, Вы писали:

Да и operator = () должен быть членом класса.
Любите книгу — источник знаний (с) М.Горький
Re[2]: vector<int> = int
От: sercher Украина  
Дата: 24.10.03 08:27
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

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


T>>Возможно ли такое?


T>>
T>>typedef vector<int> mytype;

T>>mytype& operator=(mytype& a; int b)
T>>{
T>>  a.clear();
T>>  a.push_back(b);
T>>  return a;
T>>}

T>>int main()
T>>{
T>>  mytype a = 2;
T>>  assert(a.size() == 1);
T>>  assert(a[0] == 2);
T>>  return 0;
T>>}
T>>


T>>Код конечно не компилируется.


ЗХ>угу. operator= обязан быть мембером


Или friend-ом. И объявлять надо оператор для каждого типа справа
Re: vector<int> = int
От: jazzer Россия Skype: enerjazzer
Дата: 24.10.03 08:41
Оценка:
Здравствуйте, Tan4ik, Вы писали:

T>int main()

T>{
T> mytype a = 2;
T> assert(a.size() == 1);
T> assert(a[0] == 2);
T> return 0;
T>}
T>[/ccode]

T>Код конечно не компилируется.


Вдобавок ко всем прозвучавшим пинкам добавлю свои 5 копеек:

в инструкции
T>  mytype a = 2;

происходит не вызова operator=, а вызов конструктора.
Если хочешь, чтобы вызывался operator=, пиши так
mytype a;
a = 2;


А вообще, если тебе нужна подобная функциональность, то используй не std::vector, а std::valarray (мне показалось, что он больше подойдет к твоим неозвученным нуждам)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: vector<int> = int
От: Аноним  
Дата: 24.10.03 08:44
Оценка:
Здравствуйте, Tan4ik, Вы писали:

T>Возможно ли такое?


Да.

T>typedef vector<int> mytype;

T>int main()
T>{
T>  mytype a(1, 2);
T>  assert(a.size() == 1);
T>  assert(a[0] == 2);
T>  return 0;
T>}
Re[2]: vector<int> = int
От: Bell Россия  
Дата: 24.10.03 08:46
Оценка:
Здравствуйте, jazzer, Вы писали:


J>Вдобавок ко всем прозвучавшим пинкам добавлю свои 5 копеек:


J>в инструкции

J>
T>>  mytype a = 2;
J>

J>происходит не вызова operator=, а вызов конструктора.

Я об этом говорил

J>А вообще, если тебе нужна подобная функциональность, то используй не std::vector, а std::valarray (мне показалось, что он больше подойдет к твоим неозвученным нуждам)


Да, наверное.
Любите книгу — источник знаний (с) М.Горький
Re[3]: vector<int> = int
От: Аноним  
Дата: 24.10.03 08:51
Оценка:
Здравствуйте, sercher, Вы писали:

ЗХ>>угу. operator= обязан быть мембером


S> Или friend-ом.


Нет, он не может быть friend.
Re[2]: vector<int> = int
От: Tan4ik Россия  
Дата: 24.10.03 09:42
Оценка:
J>А вообще, если тебе нужна подобная функциональность, то используй не std::vector, а std::valarray (мне показалось, что он больше подойдет к твоим неозвученным нуждам)

valarray<T>& operator=(const T& x);
member operator replaces each element of the controlled sequence with a copy of x


resize(1) ему бы сделать предварительно...
Просто фунционатьность vector меня бы вполне устроила. Сейчас написал вот так:

class myclass : public vector<int>
{
public:
    myclass& operator=(int a)
    {
        (*this).assign(1,a);
        return *this;
    }
};


Раскритикуйте если что.
---
С уважением,
Лазарев Андрей
Re[3]: vector<int> = int
От: Bell Россия  
Дата: 24.10.03 09:47
Оценка:
Здравствуйте, Tan4ik, Вы писали:


Контейнеры STL не предназначены для наследования. Лучше используй включение.
Любите книгу — источник знаний (с) М.Горький
Re[5]: vector<int> = int
От: Аноним  
Дата: 24.10.03 10:09
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

B>>Контейнеры STL не предназначены для наследования. Лучше используй включение.


ЗХ>ну, это, ИМХО, для данного случая по-барабану


ЗХ>фраза "Контейнеры STL не предназначены для наследования" означает. что у них нет виртуальных методов,


На практике она означает, что Вы получили еще одну возможность достичь неопределенного поведения без диагностики со стороны компилятора.
Re[6]: vector<int> = int
От: Зверёк Харьковский  
Дата: 24.10.03 10:24
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Зверёк Харьковский, Вы писали:


B>>>Контейнеры STL не предназначены для наследования. Лучше используй включение.


ЗХ>>ну, это, ИМХО, для данного случая по-барабану


ЗХ>>фраза "Контейнеры STL не предназначены для наследования" означает. что у них нет виртуальных методов,


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


это почему же?
FAQ — це мiй ай-кью!
Re[6]: vector<int> = int
От: Зверёк Харьковский  
Дата: 24.10.03 10:27
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, Зверёк Харьковский, Вы писали:


B>>>Контейнеры STL не предназначены для наследования. Лучше используй включение.


ЗХ>>ну, это, ИМХО, для данного случая по-барабану

B>В данном да. Но ИМХО всегда следует придеживаться определенных правил. При программировании на С++ самодисциплина играет далеко не самую последнюю роль.

правила — правилами. но для соответствующих задач нужно использовать соответствующие решения.

ЗХ>>фраза "Контейнеры STL не предназначены для наследования" означает. что у них нет виртуальных методов, которые можно было бы переопределить в наследнике.

B>В том числе у них нет виртуального деструктора.

ой. это да. тут ничего не попишешь. тормозю...

ЗХ>>...а для расширения функциональности паблик-наследование самое оно.

B>Спорное утверждение, ну да ладно...

спорное — давай спорить

ЗХ>>...а при включении пришлось бы либо делать включенный контейнер паблик-членом. что не есть гут,

B>А это еще зачем?!

а чтоб обертки не делать

ЗХ>>...либо делать обертки ко всем его операциям.

B>Да, интерфейс придется повторить. Это так ужасно?

когда нужно добавить всего 1 операцию, и ту для прикола, а больше ничего менять не надо, это — не лучшее решение. просто противно, в конце концов. сложность решения должна быть пропорциональна сложности задачи. хотя бы иногда.
FAQ — це мiй ай-кью!
Re[7]: vector<int> = int
От: Аноним  
Дата: 24.10.03 10:37
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

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


ЗХ>это почему же?


Потому, что при открытом наследовании Вы получаете возможность удалять производный объект через указатель на базовый.
Re[7]: vector<int> = int
От: Tan4ik Россия  
Дата: 24.10.03 10:37
Оценка:
ЗХ>>>фраза "Контейнеры STL не предназначены для наследования" означает. что у них нет виртуальных методов, которые можно было бы переопределить в наследнике.
B>>В том числе у них нет виртуального деструктора.
ЗХ>ой. это да. тут ничего не попишешь. тормозю...

И чем это грозит?
Извините за глупые вопросы, я на cpp недавно.
---
С уважением,
Лазарев Андрей
Re[8]: vector<int> = int
От: Аноним  
Дата: 24.10.03 10:41
Оценка:
Здравствуйте, Tan4ik, Вы писали:

B>>>В том числе у них нет виртуального деструктора.

ЗХ>>ой. это да. тут ничего не попишешь. тормозю...

T>И чем это грозит?


Неопределенным поведением при удалении через указатель на базовый класс.
Re[8]: vector<int> = int
От: Зверёк Харьковский  
Дата: 24.10.03 10:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Зверёк Харьковский, Вы писали:


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


ЗХ>>это почему же?


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


ну и что?
FAQ — це мiй ай-кью!
Re[8]: vector<int> = int
От: Tan4ik Россия  
Дата: 24.10.03 10:45
Оценка:
А>>>На практике она означает, что Вы получили еще одну возможность достичь неопределенного поведения без диагностики со стороны компилятора.

ЗХ>>это почему же?


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


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

P.S. Это уже чисто позновательный интерес.
---
С уважением,
Лазарев Андрей
Re[9]: vector<int> = int
От: Tan4ik Россия  
Дата: 24.10.03 10:47
Оценка:
T>>И чем это грозит?

А>Неопределенным поведением при удалении через указатель на базовый класс.


А в остальном все будет работать корректно?
---
С уважением,
Лазарев Андрей
Re[9]: vector<int> = int
От: Аноним  
Дата: 24.10.03 10:49
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

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


ЗХ>>>это почему же?


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


ЗХ>ну и что?


Неопределенное поведение, как и было сказано.
Re[10]: vector<int> = int
От: Аноним  
Дата: 24.10.03 10:50
Оценка:
Здравствуйте, Tan4ik, Вы писали:

T>>>И чем это грозит?


А>>Неопределенным поведением при удалении через указатель на базовый класс.


T>А в остальном все будет работать корректно?


Ну да.
Re[10]: vector<int> = int
От: Зверёк Харьковский  
Дата: 24.10.03 10:52
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Зверёк Харьковский, Вы писали:


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


ЗХ>>>>это почему же?


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


ЗХ>>ну и что?


А>Неопределенное поведение, как и было сказано.


( шизофрения, как и было сказано (c) Булгаков? )

ну при отсутствии виртуального деструктора — таки да. но с эти я уже согласился.
FAQ — це мiй ай-кью!
Re[9]: vector<int> = int
От: Зверёк Харьковский  
Дата: 24.10.03 10:56
Оценка:
Здравствуйте, Tan4ik, Вы писали:

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


ЗХ>>>это почему же?


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


T>А если я так удалять не буду? И запомню, что делаю нехорошо.

запомню — это не есть хорошо...
потом придет кто-нибудь твою прогу поддерживать — и гаплык.
насчет запомню — это целая философия.
понимаешь, многие вещи вместо того чтобы вставлять ограничения в код. можно написать в доках — не делайте того, не делайте этого.
но спасибо тебе никто не скажет
такие, блин, пирожки с котятами — их ешь, а они мяукают.

T>А если буду, но производный класс не содержит дополнительных переменных?


хрен его знает

T>P.S. Это уже чисто познавательный интерес.
FAQ — це мiй ай-кью!
Re[11]: vector<int> = int
От: Аноним  
Дата: 24.10.03 12:06
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

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


ЗХ>>>ну и что?


А>>Неопределенное поведение, как и было сказано.


ЗХ>( шизофрения, как и было сказано (c) Булгаков? )


ЗХ>ну при отсутствии виртуального деструктора — таки да.


И мне жаль! (c)
Re[10]: vector<int> = int
От: Аноним  
Дата: 24.10.03 12:08
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

T>>А если буду, но производный класс не содержит дополнительных переменных?


ЗХ>хрен его знает


Независимо. Стандарту здесь важно только несовпадение динамического и статического типов при отсутствии виртуального деструктора.
Re[8]: vector<int> = int
От: Андрей Тарасевич Беларусь  
Дата: 24.10.03 22:58
Оценка:
Здравствуйте, Аноним, Вы писали:

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


ЗХ>>это почему же?


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


Используемая Вами логика примерно аналогична совету избегать использования в С++ коде операции деления, т.к. она может привести к делению на нуль.

Это не повод избегать наследования в данном конкретном случае. Это повод не удалять производный объект через указатель на базовый, но не более.
Best regards,
Андрей Тарасевич
Re[9]: vector<int> = int
От: Аноним  
Дата: 25.10.03 08:33
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

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


АТ>Используемая Вами логика примерно аналогична совету избегать использования в С++ коде операции деления, т.к. она может привести к делению на нуль.


Вы напрасно усмотрели в моем утверждении какую-то оценочность. Ее там нет.

Я советую лишь, используя операцию деления, знать, что деление на ноль приведет к неопределенному поведению.
Re[7]: vector<int> = int
От: Зверёк Харьковский  
Дата: 25.10.03 12:38
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

[обгрызено]

великолепно!

может. вам стоит статью на тему таких суеверий написать?

с глубокоуважением, Зве
FAQ — це мiй ай-кью!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.