Собственно, тебе уже объяснили, что все вызовы в конструткорах и деструкторах — статические. А почему нельзя вызывать твою f() в деструкторах производного класса? Ведь даже если ты напишешь код этой функции, то будет вызван именно он и никакие специфические действия по очистке потомков выполнены не будут.
Да здравствует мыло душистое и веревка пушистая.
Re[2]: вызов чистой виртуальной функции в деструкторе -- как
Спасибо, я после того, как написал -- подумал и понял, что в деструкторе не выйдет, а жаль... однако переделок минимум, чтоб без наследования, так что...
Есть ещё вопросы
Поиском что-то не нашёл ответ -- это как вызвать из шаблона деструктор??? Воп пример:
struct A
{
virtual ~A();
};
template <class A>
struct B: public A
{
virtual ~B()
{
A::~A(); // очевидно, что так не выйдет
}
};
Студия 7.1. Стандарта в руках нет. Натолкнулся на такое:
class A
{
public:
virtual ~A();
private:
virtual void foo() = 0;
};
A::~A()
{
foo();
}
Компилит, но не линкует, говорит, что error LNK2019: unresolved external symbol "private: virtual void __thiscall A::foo(void)" (?foo@A@@EAEXXZ) referenced in function "public: virtual __thiscall A::~A(void)" (??1A@@UAE@XZ)
А если сделать так:
То и компилится и линкиется. Вот задумался, наверное, люди не зря сделали так, чтобы нельзя было чистую виртуальную функцию вызывать из деструктора, ну, напрмер, чтоб исключения не могло быть по причине того, что функция не реализована...Хорошее это решение через обёрточную функцию и не приведёт ли к проблемам в дальнейшем?
А сделал так вот почему: есть шаблон "наблюдатель", "субъект" вызывает у "подписчиков" при уничтожении OnDelete, что я в деструктор и запихнул; конкретный класс субъекта наследутся от интерфейса субъекта, а реализует все присущие субъекту функции шаблонный класс, ну, вот таким примерно образом:
// класс A остаётсяtemplate <class A>
class B: public A
{
private:
virtual void foo()
{
// какой-то код, одинаковый для всех наследников A
}
};
Правильный это дизайн или нет, или как лучше?
Re: вызов чистой виртуальной функции в деструкторе -- как бы
Здравствуйте, konst, Вы писали:
K>Студия 7.1. Стандарта в руках нет. Натолкнулся на такое:
Виртуальные функции из деструктора вообще не имеет смысла вызывать. Точнее никакой виртуальность ты от них не добъёшься.
K>
K>Компилит, но не линкует, говорит, что K>error LNK2019: unresolved external symbol "private: virtual void __thiscall A::foo(void)" (?foo@A@@EAEXXZ) referenced in function "public: virtual __thiscall A::~A(void)" (??1A@@UAE@XZ)
Вообще-то он должен ругаться га abstract virtual foo() called. VC конечно можно успокоить, дописав тело абстрактной функции, но имхо это не правильно. K>А если сделать так: K>
K>То и компилится и линкиется. Вот задумался, наверное, люди не зря сделали так, чтобы нельзя было чистую виртуальную функцию вызывать из деструктора, ну, напрмер, чтоб исключения не могло быть по причине того, что функция не реализована...Хорошее это решение через обёрточную функцию и не приведёт ли к проблемам в дальнейшем?
А ты код исполнять то пробовал? Сразу бы все вопросы отпали.
тут явный pure virtual function call. K>А сделал так вот почему: есть шаблон "наблюдатель", "субъект" вызывает у "подписчиков" при уничтожении OnDelete, что я в деструктор и запихнул; конкретный класс субъекта наследутся от интерфейса субъекта, а реализует все присущие субъекту функции шаблонный класс, ну, вот таким примерно образом: K>
K>// класс A остаётся
K>template <class A>
K>class B: public A
K>{
K>private:
K> virtual void foo()
K> {
K> // какой-то код, одинаковый для всех наследников A
K> }
K>};
K>
K>Правильный это дизайн или нет, или как лучше?
Не будет это работать. Во-первых зачем класс B шаблонный? Не понятно как ты собираешься это использовать. И под сомнением необходимость виртуальной функции foo.
... << RSDN@Home 1.1.3 beta 1 >>
Re[2]: вызов чистой виртуальной функции в деструкторе -- как
M>Не будет это работать. Во-первых зачем класс B шаблонный? Не понятно как ты собираешься это использовать. И под сомнением необходимость виртуальной функции foo.
struct I
{
virtual void f() = 0;
};
class A: public I
{
public:
virtual void f()
{
// что то такое
foo();
}
private:
virtual void foo() = 0;
};
class B: public I
{
public:
virtual void f()
{
// что то ещё
foo();
}
private:
virtual void foo() = 0;
};
template <class T>
class ImplFoo
{
private:
virtual void foo()
{
// что то общее для A и B
}
};
да такое часто встречается... дело не в надобности, а в том, что потребовалось в деструкторе, блин
Re[2]: вызов чистой виртуальной функции в деструкторе -- как
Здравствуйте, Vamp, Вы писали:
V>Собственно, тебе уже объяснили, что все вызовы в конструткорах и деструкторах — статические. А почему нельзя вызывать твою f() в деструкторах производного класса? Ведь даже если ты напишешь код этой функции, то будет вызван именно он и никакие специфические действия по очистке потомков выполнены не будут.
не понял.
думал, как можно решить эту проблему:
1. можно сделать с наследованием, но криво -- из деструктора потомка вызывать функцию, которая вызывает виртуальную ту, что реализует этот потомок:
class A
{
protected:
void OnDestruct()
{
f();
}
private:
virtual void f() = 0;
};
template <class A>
class B: public A
{
public:
~B()
{
A::OnDestruct();
}
private:
virtual void f()
{
// что-то
}
};
2. забить на наследование и без него неплохо получается. вообще наследование для имплементации некоторых виртуальных методов, не связанных с этой функцией...
Re[3]: вызов чистой виртуальной функции в деструкторе -- как
K>1. можно сделать с наследованием, но криво -- из деструктора потомка вызывать функцию, которая вызывает виртуальную ту, что реализует этот потомок:
....
А зачем тебе вообще OnDestruct в таком случае? Вызывай прямо f из деструктора — о чем я и сказал.
Да здравствует мыло душистое и веревка пушистая.
Re: вызов чистой виртуальной функции в деструкторе -- как бы
Ну и в конструкторе то же самое можешь получить.
Виртуальные методы в конструкторе/деструкторе вызываются статически (именно чтобы не получить abstract function call). Для этого можно определить тело абстрактного метода:
class A
{
public:
A() { method(); }
virtual void method() = 0;
};
void A::method()
{ ..... }
Естественно, что другие методы не знают, вызваны они из ктора/дтора или откуда ещё — поэтому там уже динамический вызов виртуальных методов.
А поскольку в кторе/дторе объекту устанавливаются его родные VMT (а не финального класса), то имеем бабах.
class A
{
public:
A()
// vfptr = &A::vmt
{
method(); // A::method()
invoke();
}
~A()
// vfptr = &A::vmt
{
method(); // A::method()
invoke();
}
void invoke()
{
method(); // (this->*(this->vfptr->pmethod))();
}
virtual void method() = 0;
};
// если этого не будет, то линкер не удовлетворит жажду A::A(), A::~A()void A::method() { ... }
class B : public A
{
public:
B()
// : A()
// vfptr = &B::vmt
{
invoke();
}
~B() // vfptr = &B::vmt
{
invoke();
} // ~A()void method() { ... }
};
Перекуём баги на фичи!
Re[3]: вызов чистой виртуальной функции в деструкторе -- как
K>struct I
K>{
K>virtual void f() = 0;
K>};
K>template <class T>
K>class ImplFoo
K>{
K>private:
K> void foo()
K> {
K> // что то общее для A и B
K> }
K>};
K>class A: public I, private ImplFoo<A>
K>{
K>public:
K> virtual void f()
K> {
K> // что то такое
K> foo();
K> }
K>};
K>class B: public I, private ImplFoo<B>
K>{
K>public:
K> virtual void f()
K> {
K> // что то ещё
K> foo();
K> }
K>};
K>
К тому же избавились от ненужной виртуальности.
Да, класс ImplFoo вполне может быть и не шаблонным. ;-в
... << RSDN@Home 1.1.0 stable >>
Re[3]: вызов чистой виртуальной функции в деструкторе -- как
Здравствуйте, konst, Вы писали:
K>Спасибо, я после того, как написал -- подумал и понял, что в деструкторе не выйдет, а жаль... однако переделок минимум, чтоб без наследования, так что... K>Есть ещё вопросы
K>Поиском что-то не нашёл ответ -- это как вызвать из шаблона деструктор??? Воп пример: K>
K>struct A
K>{
K> virtual ~A();
K>};
K>template <class A>
K>struct B: public A
K>{
K> virtual ~B()
K> {
K> A::~A(); // очевидно, что так не выйдет
K> }
K>};
K>
Во многом подходит такой вариант Я про то, что делал недописал малость:
struct I
{
virtual void f() = 0;
virtual void g() = 0;
};
class A: public I
{
public:
virtual void f()
{
// что то такое
foo();
}
private:
virtual void foo() = 0;
};
class B: public I
{
public:
virtual void f()
{
// что то ещё
foo();
}
private:
virtual void foo() = 0;
};
template <class T>
class ImplFoo
{
private:
virtual void foo()
{
// что то общее для A и B
}
virtual void g()
{
// имплементация g(), одинаковая для A и B
}
};
Re[5]: вызов чистой виртуальной функции в деструкторе -- как
Так, я действительно хочу понять, что ты мне пишешь, но всё равно пока не получается Я просил пример использования. То, что я хотел бы, выглядело бы так:
template <class T>
struct I1
{
tyfedef T* Param;
virtual void g(T) = 0;
virtual ~I() {}
};
struct I2: public I1<T1>
{
virtual void f() = 0;
};
struct I3: public I1<T2>
{
virtual void h() = 0;
};
class A: public I2
{
public:
virtual void f()
{
// что-то делаю
foo(p1);
}
virtual ~A()
{
foo(p2); // так нельзя! (а очень хотелось)
}
private:
virtual void foo(Param) = 0; // только объявление
};
class B: public I3
{
public:
virtual void h()
{
// что-то делаю
foo(p1);
}
private:
virtual void foo(Param) = 0; // только объявление
};
template <class T1, class T2> class ImplSome: public T1
{
public:
virtual void g(T2)
{
// имплементация чего-то
}
private:
virtual void foo(typename T1::Param p)
{
// имплементация
}
};
// всё это заканчивается такtypedef ImplSome<A, T1> AImpl;
typedef ImplSome<B, T2> BImpl;
Мне бы хотелось просто сразу двух зайцев убить: сделать в ImplSome реализацию g() публичного интерфейса и одновременно реализацию функции foo закрытого интерфейса, только беда в том, что мне её надо вызвать в деструкторе и всё, а как можно для тех же целей использовать тобой написанное?
Возможно, вот такой подход, как я описал, не является оптимальным...
Re[8]: вызов чистой виртуальной функции в деструкторе -- как
dad>как это виртальная функция с параметром о котором потомок не знает?
Простите моё костноязычие, значение параметра, которое надо передать этой функции.
Re[6]: вызов чистой виртуальной функции в деструкторе -- как
Здравствуйте, konst, Вы писали:
dad>>как это виртальная функция с параметром о котором потомок не знает? K>Простите моё костноязычие, значение параметра, которое надо передать этой функции.
проблема, наверно, в том, что ты думаешь что существует некий предолк и некий потомок
во время исполнения? Иначе, как могла возникнуть идея , что каждый клас в иерархии при уничтожении имеет какие то собственные даные , все принадлежит одному классу, и у него есь набор
деструкторов которые вызываются последовательно. Извини, если , говорю о банальных вещах.
более того там где ты расписываешь как тебе хотелось бы ты описываешь приватную функцию, как виртуальную — это невозможно и безсмысленно — вызывать в наследнике ты ее не можешь.
деструктор базового классса вызывается последним, поэтому наследники ничего делать там уже не могут.
задача:
написать такой класс который при своем уничтожении будет заставлять выполнять некторые своих функции наследников с использованием полиморфизма — невыполнима.
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re[7]: вызов чистой виртуальной функции в деструкторе -- как
dad>проблема, наверно, в том, что ты думаешь что существует некий предолк и некий потомок dad>во время исполнения?
Во время компиляции.
dad>Иначе, как могла возникнуть идея , что каждый клас в иерархии при уничтожении имеет какие то собственные даные , все принадлежит одному классу, и у него есь набор dad> деструкторов которые вызываются последовательно. Извини, если , говорю о банальных вещах. dad>более того там где ты расписываешь как тебе хотелось бы ты описываешь приватную функцию, как виртуальную — это невозможно и безсмысленно — вызывать в наследнике ты ее не можешь. dad>деструктор базового классса вызывается последним, поэтому наследники ничего делать там уже не могут.
dad>задача: dad>написать такой класс который при своем уничтожении будет заставлять выполнять некторые своих функции наследников с использованием полиморфизма — невыполнима.
Что-то эмоциональное ты написал.
1. Свою задачу я решил, но не наследованием.
2. Tonal подсказал, как с наследованием решить, попробую.
3. Вот исходный текст, минимально покоцанный, чтоб было максимально понятно (любые помидоры только приветствуются )
// subject.htemplate <typename Subscriber>
class Subject: public base::Object
{
public:
typedef Subscriber subscriber_t;
typedef Subscriber* subscriber_ptr;
typedef boost::function<void(Subscriber*)> function_t;
public:
virtual void Subscribe(subscriber_ptr) = 0;
virtual void Unsubscribe(subscriber_ptr) = 0;
};
//-----------------------------------------------
// subjimpl.htemplate <class Subject, class Subscriber>
class SubjectImpl
{
public:
void Subscribe( typename Subject::subscriber_ptr p )
{
m_subscrs.push_back(p);
}
void Unsubscribe( typename Subject::subscriber_ptr p )
{
m_subscrs.remove(p);
}
private:
void Update( typename Subject::function_t f ) const
{
std::for_each( m_subscrs.begin(), m_subscrs.end(), f );
}
std::list<Subscriber*> m_subscrs;
};
//-----------------------------------------------
// далее только применение этих шаблонов:class ISomeSubj;
struct ISomeObs
{
virtual void OnDoSome(ISomeSubj*) = 0;
virtual void OnDelete(ISomeSubj*) = 0;
};
class ISomeSubj: public Subject<ISomeObs>
{
public:
virtual void DoSome() = 0;
virtual ~ISomeSubj();
};
class SomeImpl: public ISomeSubj
{
public:
virtual void DoSome()
{
// что-то делается
Update( boost::bind(&ISomeObs::OnDoSome, _1, this) );
}
virtual ~ISomeSubj()
{
Update( boost::bind(&ISomeObs::OnDelete, _1, this) ); // чего бы хотелось, но нельзя
}
private:
virtual void Update( ISomeSubj::function_t ) const = 0;
};
typedef SubjectImpl<SomeImpl, ISomeObs> TSome;
Re[8]: вызов чистой виртуальной функции в деструкторе -- как
K>Что-то эмоциональное ты написал. K>1. Свою задачу я решил, но не наследованием. K>2. Tonal подсказал, как с наследованием решить, попробую. K>3. Вот исходный текст, минимально покоцанный, чтоб было максимально понятно (любые помидоры только приветствуются )
Это не решение с наследованием, я же говорил о твоем вопросе с решением с наследованием. Во всем остальном топик имеет отношение к проектированию, наверное.
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re[9]: вызов чистой виртуальной функции в деструкторе -- как
Здравствуйте, dad, Вы писали:
dad>Это не решение с наследованием, я же говорил о твоем вопросе с решением с наследованием. Во всем остальном топик имеет отношение к проектированию, наверное.
Хм. Не понял, ты хотел что-то сказать или спросить?
Решение с наследованием (продолжая текст выше):
class SomeFinal: public TSome
{
public:
~SomeFinal()
{
Update( boost::bind(&ISomeObs::OnDelete, _1, (ISomeSubj*)this) );
}
};
Конечно надо убрать виртуальный деструктор из SomeImpl (там я описался, написал ~ISomeSubj)...
Блин, так и думал, что ты просто потрепаться
Re[10]: вызов чистой виртуальной функции в деструкторе -- ка
dad>>Это не решение с наследованием, я же говорил о твоем вопросе с решением с наследованием. Во всем остальном топик имеет отношение к проектированию, наверное. K>Хм. Не понял, ты хотел что-то сказать или спросить?
Я хотел тебе объяснит то, что я сказал:
Задача "вызов чистой виртуальной функции в деструкторе -- как"
а именно функции реализованной в классе наследнике с параметрами переданными из деструктора родителя
не решаема решение (довольно приятное) приведенное тобой — это решение проекной задачи,
диспетчера подключений, но не твоего вопроса буквально.
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re: вызов чистой виртуальной функции в деструкторе -- как бы