C++ C+中的多态就地重建+;和/或克隆模式

C++ C+中的多态就地重建+;和/或克隆模式,c++,dynamic,constructor,destructor,polymorphism,C++,Dynamic,Constructor,Destructor,Polymorphism,我正在尝试以下技巧: class A { virtual ~A(); virtual void reset() { this->~A(); construct(); // this should magically use placement-new of the derived type on 'this', so that if called from an A pointer to a B class, it works. }

我正在尝试以下技巧:

class A {
    virtual ~A();
    virtual void reset() {
        this->~A();
        construct(); // this should magically use placement-new of the derived type on 'this', so that if called from an A pointer to a B class, it works.
    }

 };

 class B : public A {
     ...
 };
您将如何以最通用的方式实现构造

我想使用现有的默认构造函数,这是我正在添加到现有继承权的更改。我目前正在考虑两种选择:

1) construct()在每个派生类中实现,是对新位置的调用

2) 将所有构造函数移动到每个类中的init()函数。这与我们的工作方式背道而驰,也可能会导致只能用初始值设定项列表初始化的事情变得一团糟

“您将如何以最通用的方式实现构造?”


还有两点:

  • 永远不要显式调用析构函数:
    this->~A(),这会带来麻烦
  • 小心放置
    new()
    ,它不仅不适用于您的案例,而且很少符合人们通常的意愿
  • 我的两分钱,(虽然pi的答案更直接地回答你的问题)一个班级应该做一件事,一个人做一件事。通常,应该将内存管理和类实现分开。你要做的就是压缩通话

    获得相同功能最直接的方法就是使用一个非常独特的指针(C++11)

    这与您编写的“就地”重置调用完全相同,没有任何令人讨厌的副作用

    所有这些方法都有一个共同的缺陷。您必须放弃旧引用的资源,以承担新引用的资源。那里没有重用,这是一种耻辱。解决这个问题的唯一方法是提供手动“重置”功能。STL中的类通过“assign”函数实现这一点,并且通常支持的不仅仅是默认构造函数

     std::vector<int> x(100);//made a vector x of 100
     x.assign(50);//acts like x=std::vector<int>(50), but will most likely reuse the memory
    
    std::向量x(100)//使向量x等于100
    x、 分配(50)//行为类似于x=std::vector(50),但很可能会重用内存
    

    这就是PI对CRTP的反应:它是静态继承,也就是说,它执行重置函数而不受多态性的影响。

    我喜欢CRTP,尽管它并不比强迫人们编写一个调用默认构造函数而不带参数的函数更通用。我担心CRTP会让这里的人感到困惑,但我同意这是一个很好的解决方案。@tohava我对示例做了一些更改。但你是对的,它最终迫使实现者提供默认构造函数和赋值操作符。虽然这些默认情况下是由编译器提供的,但如果没有指定其他构造函数签名,我决定将您的版本与新版本一起使用。我认为你是对的。。。。除了你完全打破了原来的问题。现在,
    A
    不是不同派生类型拥有的接口。您不能有两种不同的派生类型,它必须是1个派生类型。。。如果这真的是答案,那么这个问题就相当误导了…@DavidRodríguez dribeas可以很容易地为
    reset()
    引入一个接口。我已经考虑过要展示这个,但一直到现在都没有展示。你认为这应该显示吗?如果您愿意,也可以随意编辑。这不起作用,因为您不能假设在对象销毁后v-table指针仍然有效(IIRC每个析构函数将其设置为当前已销毁的类,尽管它可能是特定于编译器的)。只需在派生类中实现reset()。@JarkkoL,我可以定义一个虚拟函数,它通过构造函数调用返回lambda,在销毁之前调用该函数,然后执行销毁,然后调用返回的lambda。@tohava:您试图解决错误的问题。或者换一种说法,你问的是如何实现错误的解决方案。你建议使用
    std::unique_ptr
    ,对于这种情况,甚至可以与旧的
    std::auto_ptr
    很好地配合使用(大多数情况下,我认为它们在内部是等效的)。
     B b;
     AA* vp = &b;
    
     vp->reset();
    
    std::unique_ptr<A> a(new B());
    a.reset(new B());//deletes the old B and makes a new B.
    
     B a;//old reference
     a = B();//Reset!
    
     std::vector<int> x(100);//made a vector x of 100
     x.assign(50);//acts like x=std::vector<int>(50), but will most likely reuse the memory