Вызов вирт. метода из родительского деструктора
От: sanx  
Дата: 05.12.10 00:16
Оценка:
Как я понимаю такое невозможно (вот здесь читал http://easy-coding.blogspot.com/2009/09/blog-post.html). Но вот у меня такая задача:

class BaseClass
{
public:
~BaseClass() { Free(); }
void Free() { ЧТО-ТО_ОБЩЕЕ_ДЛЯ_ВСЕХ; FreeResource(); }
protected:
virtual void FreeResource() = 0;
};

Метод Free нужен публичный, он делает некоторые вещи (по освобождению ресурсов) общие для всех унаследованных классов, и плюс каждый класс должен не забыть реализовать метод освобождения специфических для него ресурсов FreeResource. Но понятно что в деструкторе будет вызываться чисто виртуально абстрактный метод базового класса (FreeResource() = 0). Как быть?
виртуальный метод деструктор
Re: Вызов вирт. метода из родительского деструктора
От: Centaur Россия  
Дата: 05.12.10 04:12
Оценка:
Здравствуйте, sanx, Вы писали:

S>class BaseClass
S>{
S>public:
S>    ~BaseClass() { Free(); }
S>    void Free() { ЧТО-ТО_ОБЩЕЕ_ДЛЯ_ВСЕХ; FreeResource(); }
S>protected:
S>    virtual void FreeResource() = 0;
S>};


S>Метод Free нужен публичный, он делает некоторые вещи (по освобождению ресурсов) общие для всех унаследованных классов, и плюс каждый класс должен не забыть реализовать метод освобождения специфических для него ресурсов FreeResource. Но понятно что в деструкторе будет вызываться чисто виртуально абстрактный метод базового класса (FreeResource() = 0). Как быть?


Это неправильный дизайн. Сделайте, чтобы освобождение ресурсов выполнялось только при уничтожении объекта, в (виртуальном) деструкторе. Вместо вызова функции Free устройте, чтобы в этом месте объект уничтожился, например, введением дополнительного scope.
Re: Вызов вирт. метода из родительского деструктора
От: sergey_shandar США http://getboost.codeplex.com/
Дата: 05.12.10 04:20
Оценка:
Здравствуйте, sanx, Вы писали:

S>Метод Free нужен публичный, он делает некоторые вещи (по освобождению ресурсов) общие для всех унаследованных классов, и плюс каждый класс должен не забыть реализовать метод освобождения специфических для него ресурсов FreeResource. Но понятно что в деструкторе будет вызываться чисто виртуально абстрактный метод базового класса (FreeResource() = 0). Как быть?


Почему бы не объявить виртуальный деструктор?
class BaseClass
{
public:
    virtual ~BaseClass() { /* что то общее для всех */; }
};
getboost.codeplex.com
citylizard.codeplex.com
Re: Вызов вирт. метода из родительского деструктора
От: ilnar Россия  
Дата: 05.12.10 08:08
Оценка:
Здравствуйте, sanx, Вы писали:

S>Как я понимаю такое невозможно (вот здесь читал http://easy-coding.blogspot.com/2009/09/blog-post.html). Но вот у меня такая задача:


S>class BaseClass

S>{
S>public:
S> ~BaseClass() { Free(); }
S> void Free() { ЧТО-ТО_ОБЩЕЕ_ДЛЯ_ВСЕХ; FreeResource(); }
S>protected:
S> virtual void FreeResource() = 0;
S>};

S>Метод Free нужен публичный, он делает некоторые вещи (по освобождению ресурсов) общие для всех унаследованных классов, и плюс каждый класс должен не забыть реализовать метод освобождения специфических для него ресурсов FreeResource. Но понятно что в деструкторе будет вызываться чисто виртуально абстрактный метод базового класса (FreeResource() = 0). Как быть?


то, что вы хотите сделать, уже придумано, и даже в лучшем чем вы задумали виде.
называется виртуальныц деструктор, почитайте внимательно про него
Re: Вызов вирт. метода из родительского деструктора
От: Kerbadun  
Дата: 05.12.10 11:08
Оценка:
Единственное решение, которое приходит на ум — это использовать CRTP (Curiously recurring template pattern):

template <class DerivedType>
class BaseClass
{
public:
virtual ~BaseClass() { Free(); }
void Free() { ЧТО-ТО_ОБЩЕЕ_ДЛЯ_ВСЕХ; static_cast<DerivedType*>(this)->FreeResource(); }
protected:
virtual void FreeResource() = 0;
};

class DerivedClass : public BaseClass<DerivedClass>
{
public:

protected:

    void FreeResource() 
    {
    }
};

Когда он умрет, его мозг заспиртуют в стакане
Re[2]: Вызов вирт. метода из родительского деструктора
От: wander  
Дата: 05.12.10 12:09
Оценка: 3 (1)
Здравствуйте, Kerbadun, Вы писали:

K>
K>template <class DerivedType>
K>class BaseClass
K>{
K>public:
K>virtual ~BaseClass() { Free(); }
K>void Free() { ЧТО-ТО_ОБЩЕЕ_ДЛЯ_ВСЕХ; static_cast<DerivedType*>(this)->FreeResource(); }
K>protected:
K>virtual void FreeResource() = 0;
K>};

K>class DerivedClass : public BaseClass<DerivedClass>
K>{
K>public:

K>protected:
K>    void FreeResource() 
K>    {
K>    }
K>};
K>


Это не будет работать. FreeResource вызывается в деструкторе базового класса, в это время наследник уже уничтожен, следовательно получим вызов чисто виртуального метода, что есть неизбежное падение программы. Во-вторых у тебя FreeResource у наследника в protected, так что надо либо friend использовать, либо переносить в public. А лучше вообще так не делать. Я тут уже как-то давно писал, что CRTP противопоказано для конструкторов и деструкторов.
Re[3]: Вызов вирт. метода из родительского деструктора
От: Kerbadun  
Дата: 05.12.10 21:56
Оценка:
W>Это не будет работать. FreeResource вызывается в деструкторе базового класса, в это время наследник уже уничтожен, следовательно получим вызов чисто виртуального метода, что есть неизбежное падение программы. Во-вторых у тебя FreeResource у наследника в protected, так что надо либо friend использовать, либо переносить в public. А лучше вообще так не делать. Я тут уже как-то давно писал, что CRTP противопоказано для конструкторов и деструкторов.

Да, стормозил.

А какое решение здесь можно предложить?

Когда он умрет, его мозг заспиртуют в стакане
Re[4]: Вызов вирт. метода из родительского деструктора
От: slava_phirsov Россия  
Дата: 06.12.10 11:57
Оценка:
Здравствуйте, Kerbadun, Вы писали:

K>А какое решение здесь можно предложить?


Виртуальный деструктор в действии

Еще можно как-то попробовать закрытый деструктор + псевдодеструктор, правда, это не будет работать в том случае, если мы хотим размещать экземпляры класса не в куче, а на стеке. Но мне как-то не догнать почему виртуальный деструктор не годится для ваших целей. Приведи, плиз, минимальный пример использования класса.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[5]: Вызов вирт. метода из родительского деструктора
От: Kerbadun  
Дата: 06.12.10 18:47
Оценка: 1 (1)
_>Виртуальный деструктор в действии

_>Еще можно как-то попробовать закрытый деструктор + псевдодеструктор, правда, это не будет работать в том случае, если мы хотим размещать экземпляры класса не в куче, а на стеке. Но мне как-то не догнать почему виртуальный деструктор не годится для ваших целей. Приведи, плиз, минимальный пример использования класса.


Я не топикстартер, но виртуальный деструктор ничего не дает, так как автор хочет вызывать из базового класса виртуальную функцию FreeResource, а в деструкторе, как известно, виртуальные функции не работают.

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

Я пока что-то вообще не вижу никакого (во всяком случае, автоматического и приличного) решения этой проблемы в C++. Разве что, как сказали, менять архитектуру.

Когда он умрет, его мозг заспиртуют в стакане
Re: Вызов вирт. метода из родительского деструктора
От: GreyMan  
Дата: 07.12.10 02:13
Оценка:
Здравствуйте, sanx, Вы писали:

S>Как я понимаю такое невозможно (вот здесь читал http://easy-coding.blogspot.com/2009/09/blog-post.html). Но вот у меня такая задача:


S>class BaseClass

S>{
S>public:
S> ~BaseClass() { Free(); }
S> void Free() { ЧТО-ТО_ОБЩЕЕ_ДЛЯ_ВСЕХ; FreeResource(); }
S>protected:
S> virtual void FreeResource() = 0;
S>};

S>Метод Free нужен публичный, он делает некоторые вещи (по освобождению ресурсов) общие для всех унаследованных классов, и плюс каждый класс должен не забыть реализовать метод освобождения специфических для него ресурсов FreeResource. Но понятно что в деструкторе будет вызываться чисто виртуально абстрактный метод базового класса (FreeResource() = 0). Как быть?


class BaseClass
{
protected:
     std::function<void(bool)> clear;//C++0x. или буст тогда
public:
    ~BaseClass() { Free(true); }
    void Free(bool callFromDestructor=false) 
        { 
        ЧТО-ТО_ОБЩЕЕ_ДЛЯ_ВСЕХ; 
        clear(callFromDestructor); 
        }

};

И инициализировать в конструкторе производного класса. Проблема с неопреленным состоянием после вызова деструктора потомка, правда никуда не денется..
Re: Вызов вирт. метода из родительского деструктора
От: Caracrist https://1pwd.org/
Дата: 07.12.10 06:31
Оценка: 2 (1)
Здравствуйте, sanx, Вы писали:

S> Как быть?


смотри в сторону обёртки типа того что делают для COM объектов...

template<typename T>
class Disposable {
public:
  Disposable(T * val) : m_value(val) {}
  ~Disposable() { m_value->Dispose(); delete m_value;}
  T& operator*{retrun *m_value;} 
  T * operator->{return m_value;}
private:
  T * m_value;
};
~~~~~
~lol~~
~~~ Single Password Solution
Re[6]: Вызов вирт. метода из родительского деструктора
От: slava_phirsov Россия  
Дата: 07.12.10 07:08
Оценка:
Здравствуйте, Kerbadun, Вы писали:

K>Я не топикстартер, но виртуальный деструктор ничего не дает, так как автор хочет вызывать из базового класса виртуальную функцию FreeResource, а в деструкторе, как известно, виртуальные функции не работают.


Вот и не понятно: что значит из базового класса? Если из деструктора базового класса — то это ИМХО не имеет смысла, т.к. к моменту вызова деструктора базового класса производный класс уже уничтожен (если конечно не рассматривать экзотический случай явного вызова деструктора). Если при уничтожении объекта, с которым мы работаем через указатель на экземпляр базового класса — то это и есть область применения виртуального деструктора.

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


Ну, об этом можно было и не напоминать

K>Я пока что-то вообще не вижу никакого (во всяком случае, автоматического и приличного) решения этой проблемы в C++. Разве что, как сказали, менять архитектуру.


Псевдодеструктор, вызывающий виртуальную функцию, а затем — настоящий деструктор. Но назвать это решение приличным как-то не поворачивается язык. Что-то типа того, что описывается чуть ниже
Автор: Caracrist
Дата: 07.12.10
. Конечно, придется закрыть деструктор, иначе никто не помешает клиенту вызывать delete вместо нашего псевдодеструктора; объекты при этом нельзя будет размещать на стеке. Правда, ничто не в силах запретить клиенту создать производный класс с открытым деструктором, что разнесет нашу башню из моржовой кости на куски. Ну это так, мысли вслух, в порядке легкого бреда
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[7]: Вызов вирт. метода из родительского деструктора
От: slava_phirsov Россия  
Дата: 07.12.10 07:20
Оценка:
Здравствуйте, slava_phirsov, Вы писали:

_>Что-то типа того, что описывается чуть ниже
Автор: Caracrist
Дата: 07.12.10
.


А, нет, это не совсем то, сорри.
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[6]: Вызов вирт. метода из родительского деструктора
От: _nn_  
Дата: 08.12.10 09:47
Оценка:
Здравствуйте, Kerbadun, Вы писали:

K>Я пока что-то вообще не вижу никакого (во всяком случае, автоматического и приличного) решения этой проблемы в C++. Разве что, как сказали, менять архитектуру.


Можно на базе Trick CRTP v3.0
Автор: remark
Дата: 02.10.07
это сделать.
http://rsdn.nemerleweb.com
http://nemerleweb.com
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.