[C++] деструктор при множественном наследовании
Или дописать
Это ничему не повредит и стандарту не противоречит. Как workaround.
Но имхо, это, конечно, не нормально.
Base::~Base {}Это ничему не повредит и стандарту не противоречит. Как workaround.
Но имхо, это, конечно, не нормально.
что такое абстрактный деструктор, и зачем это надо?
Да, кстати, это тоже workaround, потому что в C++ нету ключевого слова abstract, которое можно было бы навесить на класс. Так что воркэраундить воркэраунд — это нормально, тем более в C++.
12.4.7 A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly- declared) is virtual.
То есть код ТС нарушает стандарт, а компилятор, вроде как, все правильно сделал.
То есть код ТС нарушает стандарт, а компилятор, вроде как, все правильно сделал.
Ты про «shall be defined»? Вроде бы это shall, а не must. Короче что-то я не понял.
Да, имею ввиду это.
См. rfc2119:
1. MUST This word, or the terms "REQUIRED" or "SHALL", mean that the
definition is an absolute requirement of the specification.
См. rfc2119:
1. MUST This word, or the terms "REQUIRED" or "SHALL", mean that the
definition is an absolute requirement of the specification.
if any objects of that class or any derived class are created in the program, the destructor shall be definedА, понятно. Тут даже множественное наследование не при чем. Вот это аналогично не работает:
struct Base
{
virtual ~Base = 0;
};
struct Target : public Base
{
~Target {}
};
int main
{
Target* t = new Target;
delete t;
return 0;
}
По-любому нужно определение.
что такое абстрактный деструктор, и зачем это надо?Я подзабыл и думал, что можно объявить аналогично абстрактной функции абстрактный деструктор: virtual ~Base = 0. Оно и можно, только его определение все равно нужно предоставить, оказывается.
Я подзабылиз той же серии:
1) можно создать экземпляр
http://codepad.org/4AYt77Ui
2) нельзя создать экземпляр
http://codepad.org/HXLhyByS и линкуется http://codepad.org/3dqP1uop
А да, затупил.
ха-ха-ха, вот это сюрприз! Выходит я такие штуки g++ никогда и не компилил 

// что такое абстрактный деструктор, и зачем это надо?
Если хочется сделать класс абстрактным, а чисто виртуальных методов нет, можно объявить чисто виртуальным деструктор. Определить его всё равно придётся, естественно.
Если хочется сделать класс абстрактным, а чисто виртуальных методов нет, можно объявить чисто виртуальным деструктор. Определить его всё равно придётся, естественно.
>Определить его всё равно придётся, естественно.
вот эта концепция в меня совсем не укладывается...
как можно абстрактный метод(деструктор) при этом еще и определить... либо шубу снять надо, либо трусы одеть..(C)
вот эта концепция в меня совсем не укладывается...
как можно абстрактный метод(деструктор) при этом еще и определить... либо шубу снять надо, либо трусы одеть..(C)
И не надо ее в себя укладывать,
не даром же говорят, что c++ cripples
mind...
не даром же говорят, что c++ cripples
mind...
Ну, кстати, я подумал, это и правда естественно (раньше мне так не казалось просто потому что деструкторы в C++ неявно автоматически вызывают унаследованный деструктор, для обычных функций это, естественно не так.
Ну а про чисто виртуальную функцию и ее определение, это надо просто привыкнуть: чистая виртуальность — значит надо явно указать, что хочешь вместо нее, но можно предоставить реализацию по умолчанию. Вроде в некоторых местах так рекомендуют делать (специалисты по шаблонам гыгы)
Ну а про чисто виртуальную функцию и ее определение, это надо просто привыкнуть: чистая виртуальность — значит надо явно указать, что хочешь вместо нее, но можно предоставить реализацию по умолчанию. Вроде в некоторых местах так рекомендуют делать (специалисты по шаблонам гыгы)
Кстати, нашел небесполезную статью по теме.
прочитал. Еще прочитал ответ (в жежешечке). Мысль про виртуальные открытые функции — очень хорошая, про защищенный деструктор — пурга имхо.
Ну я не то чтобы ратую сам за protected virtual ~,
но точка зрения такая небезынтересна.
но точка зрения такая небезынтересна.
разжуй для меня, пожалуйста! Вот я тоже еще сперва подумал, что он имеет в виду защищенный виртуальный, но там у него написано защищенный НЕ виртуальный. И вообще, если уж так заморачиваться и публичные методы делать невиртуальными, то защищенные тоже надо бы, protected — это ведь тоже интерфейс, просто на другом уровне.
Да я эту статью, честно говоря, по диагонали
проглядел. Вообще protected ~, хоть виртуальный,
хоть нет, это трюк для людей, которым
хочется странного.
проглядел. Вообще protected ~, хоть виртуальный,
хоть нет, это трюк для людей, которым
хочется странного.
Ну да, тут не уйдешь, типа разрешить наследование, но запретить создание на стеке. Ок.
Обычно, и вправду, когда реализуют на cxx template method,
используют private virtual.
Область применения protected virtual мне сходу не очевидна.
используют private virtual.
Область применения protected virtual мне сходу не очевидна.
Дааа, template method — брат полиморфизма!
Тут ирония, или
мне почудилось?
мне почудилось?
Почудилось наверное. Типа мне кажется, что где виртуальные фукнции там обязательно template method в некотором смысле.
Я тоже так cчитаю, хотя в "несерьезных"
проектах сам частенько нарушаю NVI принцип,
и тогда здесь TM уже и не пахнет
проектах сам частенько нарушаю NVI принцип,
и тогда здесь TM уже и не пахнет

Кстати, вот одно небесполезное
применение: сделать некий базовый
класс с защищенным деструктором и
зафрендить shared_ptr. Потом
заставить всех от него наследоваться.
Так можно принудить подчиненных
кодомакак не использовать delete
где не надо.
применение: сделать некий базовый
класс с защищенным деструктором и
зафрендить shared_ptr. Потом
заставить всех от него наследоваться.
Так можно принудить подчиненных
кодомакак не использовать delete
где не надо.
Firefox не может найти сервер shared_ptr.livejournal.com.
fixed 

ROTFLMAO
сделать некий базовыйвы так делали? у вас компилируется код?
класс с защищенным деструктором и
зафрендить shared_ptr.
что-то мне подсказывает, что это не работает

УМВРЧЯДНТ?
#include <tr1/memory>
#include <iostream>
using std::tr1::shared_ptr;
using std::cerr;
class B {
friend class std::tr1::_Sp_deleter<B>;
protected:
virtual ~B {
cerr<<"~B\n";
}
};
class D1: public B {
protected:
~D1 {
cerr<<"~D1\n";
}
};
class D2: public B {
~D2 {
cerr<<"~D2\n";
}
};
int main {
shared_ptr<B> b(static_cast<B*>(new D1;
return 0;
}
friend class std::tr1::_Sp_deleter<B>;
shared_ptr<B> b(static_cast<B*>(new D1;

"Никто не обещал, что будет легко
Я понимаю тебя, Садко,
Но мое чувство юмора рекомендует мне всплыть."
(c) БГ
Я понимаю тебя, Садко,
Но мое чувство юмора рекомендует мне всплыть."
(c) БГ
Да не, ну косяк же, имхо 

Блин, да я эту хрень писал
в метро с телефона и на нем
же компиляйнил, че ты хочешь

А вообще реальная тема:
1) Работает
2) Кодомакаки все равно не поймут
в метро с телефона и на нем
же компиляйнил, че ты хочешь

А вообще реальная тема:
1) Работает
2) Кодомакаки все равно не поймут
Не, ну tr1 — это не по-людски.
А что по-людски, cxx0x?
На самом деле и cxx0x до принятия не до конца кошерен, хотя кто ж спорит, юзать удобно и хочется.
Но у него есть существенное преимущество перед tr1 — у всего, что лежит в tr1, с очень большой вероятностью постепенно «поломаются» и инклюды, и неймспейс.
Но у него есть существенное преимущество перед tr1 — у всего, что лежит в tr1, с очень большой вероятностью постепенно «поломаются» и инклюды, и неймспейс.
Ну блин, если поломаются —
поправлю пост, уговорил
поправлю пост, уговорил

добавил gcc твоего участка в cron, будь готов.
Жду ответного гудка.
О, пришел ответ:
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4/include/g++-v4/tr1/memory:60,
from <stdin>:1:
<stdin>: In constructor ‘std::tr1::__shared_count<_Lp>::__shared_count(_Ptr) [with _Ptr = B*, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]’:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4/include/g++-v4/tr1/shared_ptr.h:377: instantiated from ‘std::tr1::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Tp1*) [with _Tp1 = B, _Tp = B, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]’
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4/include/g++-v4/tr1/shared_ptr.h:842: instantiated from ‘std::tr1::shared_ptr<_Tp>::shared_ptr(_Tp1*) [with _Tp1 = B, _Tp = B]’
<stdin>:29: instantiated from here
<stdin>:10: error: ‘virtual B::~B’ is protected
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4/include/g++-v4/tr1/shared_ptr.h:119: error: within this context
Ну что я могу тут сказать?..
У меня на телефоне 4.2.2, там
работает. С тех пор поменяли
реализацию shared_ptr.
Щас поправлюю
У меня на телефоне 4.2.2, там
работает. С тех пор поменяли
реализацию shared_ptr.
Щас поправлюю
О, вот так надо:
#include <tr1/memory>
#include <iostream>
using std::tr1::shared_ptr;
using std::cerr;
class B {
friend class std::tr1::_Sp_deleter<B>;
friend class std::tr1::__shared_count<(__gnu_cxx::_Lock_policy)2u>;
protected:
virtual ~B {
cerr<<"~B\n";
}
};
class D1: public B {
protected:
~D1 {
cerr<<"~D1\n";
}
};
class D2: public B {
~D2 {
cerr<<"~D2\n";
}
};
int main {
shared_ptr<B> b(static_cast<B*>(new D1;
return 0;
}
О, вот так надо:ну вы же понимаете, что это непортабельное решение, потому что вы используете нюансы имплементации
остановитесь

Давайте Вашу имплементацию,
портируем
портируем

Оставить комментарий
erotic
Это нормально? Судя по всему, деструктор Target хочет вызвать деструкторы обоих базовых классов, но определения одного из них нет.
Если это так, то выходит, что интерфейсные классы с абстрактным деструктором нельзя использовать во множественном наследовании, не создав промежуточный класс с определенным деструктором, или просто не определив где-то вовне деструктор такого абстрактного класса.
А как в других компиляторах и по стандарту?