[C++] деструктор при множественном наследовании
Base::~Base {}
Это ничему не повредит и стандарту не противоречит. Как workaround.
Но имхо, это, конечно, не нормально.
что такое абстрактный деструктор, и зачем это надо?
Да, кстати, это тоже workaround, потому что в C++ нету ключевого слова abstract, которое можно было бы навесить на класс. Так что воркэраундить воркэраунд — это нормально, тем более в C++.
То есть код ТС нарушает стандарт, а компилятор, вроде как, все правильно сделал.
Ты про «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.
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++ cripples
mind...
Ну а про чисто виртуальную функцию и ее определение, это надо просто привыкнуть: чистая виртуальность — значит надо явно указать, что хочешь вместо нее, но можно предоставить реализацию по умолчанию. Вроде в некоторых местах так рекомендуют делать (специалисты по шаблонам гыгы)
статью по теме.
Кстати, нашел небесполезную
прочитал. Еще прочитал ответ (в жежешечке). Мысль про виртуальные открытые функции — очень хорошая, про защищенный деструктор — пурга имхо.
но точка зрения такая небезынтересна.
разжуй для меня, пожалуйста! Вот я тоже еще сперва подумал, что он имеет в виду защищенный виртуальный, но там у него написано защищенный НЕ виртуальный. И вообще, если уж так заморачиваться и публичные методы делать невиртуальными, то защищенные тоже надо бы, protected — это ведь тоже интерфейс, просто на другом уровне.
проглядел. Вообще protected ~, хоть виртуальный,
хоть нет, это трюк для людей, которым
хочется странного.
Ну да, тут не уйдешь, типа разрешить наследование, но запретить создание на стеке. Ок.
Обычно, и вправду, когда реализуют на cxx template method,
Дааа, template method — брат полиморфизма!
мне почудилось?
Почудилось наверное. Типа мне кажется, что где виртуальные фукнции там обязательно template method в некотором смысле.
проектах сам частенько нарушаю NVI принцип,
и тогда здесь TM уже и не пахнет
применение: сделать некий базовый
класс с защищенным деструктором и
зафрендить 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) БГ
Да не, ну косяк же, имхо
в метро с телефона и на нем
же компиляйнил, че ты хочешь
А вообще реальная тема:
1) Работает
2) Кодомакаки все равно не поймут
Не, ну tr1 — это не по-людски.
А что по-людски, cxx0x?
Но у него есть существенное преимущество перед 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.
Щас поправлюю
#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 хочет вызвать деструкторы обоих базовых классов, но определения одного из них нет.
Если это так, то выходит, что интерфейсные классы с абстрактным деструктором нельзя использовать во множественном наследовании, не создав промежуточный класс с определенным деструктором, или просто не определив где-то вовне деструктор такого абстрактного класса.
А как в других компиляторах и по стандарту?