Is appropriate to call virtual function in derived class destructor?
我有一个继承,基类的析构函数应用模板方法模式。析构函数在调用虚clean函数之前必须做一些工作,在调用之后还要做一些其他工作。
我们知道在构建或破坏过程中永远不要调用虚拟函数。所以下面的代码绝对不可用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | class base { public: virtual ~base() { // ... do something before do_clear() do_clear(); // ... do something after do_clear() } private: virtual void do_clear() = 0; }; class d1 : public base { public: d1() : m_x(new int) {} ~d1() {} private: virtual void do_clear() { delete m_x; } int *m_x; }; |
但如果我将进程的销毁移到派生类的析构函数,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | class base { public: virtual ~base() { } protected: void clear() { // ... do something before do_clear() do_clear(); // ... do something after do_clear() } private: virtual void do_clear() = 0; }; class d1 : public base { public: d1() : m_x(new int) {} ~d1() { clear(); } private: virtual void do_clear() { delete m_x; } int *m_x; }; |
如果客户写下:
1 2 | base *x = new d1; delete x; |
它先调用
我的问题是:
您当前的设计有两个问题。第一,它违反了五法则/零法则。这意味着这些类的正常使用几乎肯定会导致内存泄漏或双重删除。
第二个问题是,您使用继承来建模一些可能更好地用组合建模的东西。
以下是我如何编写此代码(使用wheels::value_ptr):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | struct D_interface { //Providing virtual functions for run-time modifiable behaviour virtual D_interface *clone() const = 0; virtual ~D_interface(){} }; struct D_Delete { //Here is the code to call through to the virtual `D` object behaviour: void operator()(D_interface *p) { // ... do something before delete p; delete p; // ... do something after delete p; } //Put (pointers to) relevant data here, //initialise them when constructing the `value_ptr`, or //at a later stage with get_deleter }; struct d1 : D_interface { wheels::value_ptr<int> mx; virtual D_interface *clone() const { return new d1(*this); } }; //Nothing derives from `base`, because the polymorphism that is needed is internal //to the implementation of `base` //To add new functionality, add a new `D_interface` implementation. class base { wheels::value_ptr<D_interface, wheels::DefaultCloner<D_interface>, D_Delete> D_impl; public: base(D_interface *D_impl) : D_impl(D_impl) { } }; |
对于我来说,我认为这个模式是确定的,因为您需要在派生类中实现虚函数。这就是虚拟课堂的哲学。