是否有实施后的构造函数和析构函数预虚方法调用任何自动化的方式?(Is there any autom

2019-06-26 08:30发布

由于与调用来自内部构造和析构虚方法众所周知的问题,我通常与需要最终设置方法只是其构造后调用类和拆除前法结束了之前被称为他们的析构函数,就像这样:

MyObject * obj = new MyObject;
obj->Initialize();   // virtual method call, required after ctor for (obj) to run properly
[...]
obj->AboutToDelete();  // virtual method call, required before dtor for (obj) to clean up properly
delete obj;

这工作,但它承载的是,来电者会忘记调用这些方法之一或两者在适当的时间风险。

所以,问题是:有没有C ++没有办法让那些被自动调用方法,所以调用者不必记得你给他们打电话? (我猜没有,但我认为我会问反正以防万一有一些聪明的办法做到这一点)

Answer 1:

与添加后的构造函数C ++的主要问题是,没有人尚未建立如何应对后后构造,后后后的构造函数等

基本的理论是,对象有不变量。 这不变的是由构造确定。 一旦它已经建立,这个类的方法可以调用。 随着引进,要求后的构造设计的,您将引入其中一旦构造函数运行不成为既定类不变量的情况。 因此,这将是同样不安全,让从后构造虚函数调用,你立即失去他们似乎有一个明显的好处。

当你的例子显示了(可能是你没有意识到),他们没有必要:

MyObject * obj = new MyObject;
obj->Initialize();   // virtual method call, required after ctor for (obj) to run properly

obj->AboutToDelete();  // virtual method call, required before dtor for (obj) to clean up properly
delete obj;

让我们来说明为什么不需要这些方法。 这两个电话可以调用虚函数MyObject或它的基地之一。 然而, MyObject::MyObject()可以安全地调用这些函数了。 没有什么发生这种情况后, MyObject::MyObject()返回这将使obj->Initialize()是安全的。 因此,无论obj->Initialize()是错误的或它的呼叫可以被转移到MyObject::MyObject() 同样的逻辑适用于反向obj->AboutToDelete() 最衍生的析构函数将首先运行,它仍然可以调用所有虚拟功能,包括AboutToDelete()



Answer 2:

虽然没有自动化的方式,你可以通过拒绝用户访问该类型的析构函数,并宣布一个特别的删除方法迫使用户的手。 在这种方法中,你可以做你想要的虚拟电话。 创建可以采取类似的做法,静态工厂方法。

class MyObject {
  ...
public:
  static MyObject* Create() { 
    MyObject* pObject = new MyObject();
    pObject->Initialize();
    return pObject;
  }
  Delete() {
    this->AboutToDelete();
    delete this;
  }
private:
  MyObject() { ... }
  virtual ~MyObject() { ... }
};

现在是不是可以调用“删除OBJ;” 除非通话网站访问myObject的私有成员。



Answer 3:

我能想到的最好的是你与新闻了一个实例,并调用初始化静态创建方法,实现自己的智能指针,并在其析构函数调用AboutToDelete,然后删除。



Answer 4:

我使用非常仔细地设计Create()工厂方法(每个类的静态成员)来调用以相同的顺序一个构造函数和初始值设定为对C#初始化类型。 它返回shared_ptr的类型的实例,保证堆分配。 事实证明可靠且随着时间的推移保持一致。

诀窍:我生成我的C ++类的声明从XML ...



Answer 5:

除了JavedPar的想法对于销毁前方法,没有预制备溶液容易地做两阶段构造/销毁在C ++中。 最明显的方式做到这一点,是按照最常见的回答一些问题在C ++:“添加间接的另一层” 您可以在另一个对象中包装这个类层次的对象。 然后,该对象的构造函数/析构函数可以调用这些方法。 看看Couplien的信,信封成语,例如,或者使用已经提出的智能指针的方法。



Answer 6:

http://www.research.att.com/~bs/wrapper.pdf本文从斯特劳斯将解决你的问题。

我2008年VS之下,在Ubuntu上对G ++编译器测试这一点。 它工作得很好。

#include <iostream>

using namespace std;

template<class T>

class Wrap
{
    typedef int (T::*Method)();
    T* p;
    Method _m;
public:
    Wrap(T*pp, Method m): p(pp), _m(m)  { (p->*_m)(); }
    ~Wrap() { delete p; }
};

class X
{
public:
    typedef int (*Method)();
    virtual int suffix()
    {
        cout << "X::suffix\n";
        return 1;
    }

    virtual void prefix()
    {
        cout << "X::prefix\n"; 
    }

    X() {  cout << "X created\n"; }

    virtual ~X() { prefix(); cout << "X destroyed\n"; }

};

class Y : public X
{
public:
    Y() : X() { cout << "Y created\n"; }
    ~Y() { prefix(); cout << "Y destroyed\n"; }
    void prefix()
    {
        cout << "Y::prefix\n"; 
    }

    int suffix()
    {
        cout << "Y::suffix\n";
        return  1;
    }
};

int main()
{
    Wrap<X> xx(new X, &X::suffix);
    Wrap<X>yy(new Y, &X::suffix);
}


Answer 7:

我被卡住了同样的问题,以及一些研究之后,我相信没有任何标准的解决方案。

我最喜欢的建议是在Aleksandrescu等人提供的。 书“C ++编码标准”中的第49项。

引述他们(合理使用),你有几种选择:

  1. 只需将其记录下来,你需要第二个方法,像你一样。
  2. 有一个标志,如果施工后已经发生另一个内部状态(布尔)
  3. 使用虚拟类语义,在这个意义上,最派生类的构造函数决定使用哪个基类
  4. 使用工厂函数。

见他对细节的书。



Answer 8:

您可以在类中使用静态函数模板。 随着私家构造函数/析构函数。 在vs2015社会运行

class A {
    protected:
    A() {}
        virtual ~A() {}
        virtual void onNew() = 0;
        virtual void onDelete() = 0;
    public:

        void destroy() {
            onDelete();
            delete this;
        }

        template <class T> static T* create() {
            static_assert(std::is_base_of<A, T>::value, "T must be a descendant of A");
            T* t = new T();
            t->onNew();
            return t;
        }
   };

class B: public A {
     friend A;

     protected:
          B() {}
          virtual ~B() {}

          virtual void onNew() override {
          }

          virtual void onDelete() override {
          }
};

int main() {
    B* b;
    b = A::create<B>();
    b->destroy();
}


Answer 9:

还没有看到答案,但基类是唯一一个在类层次结构添加代码的方式。 您还可以创建设计要添加到层次结构的另一面类:

template<typename Base> 
class Derived : public Base {
    // You'd need C++0x to solve the forwarding problem correctly.
    Derived() : Base() {
        Initialize();
    }
    template<typename T>
    Derived(T const& t): Base(t) {
        Initialize();
    }
    //etc
private:
    Initialize();
};


文章来源: Is there any automated way to implement post-constructor and pre-destructor virtual method calls?