如何始终通过某种方法来强制执行该构造?

问题描述

我有一些第三方抽象基类

struct foo
{
    virtual foo*job() = 0;
    ...
    static void* make_space(size_t sizeofDerived);
};

我无法更改。类型foo(以及所有派生类)的对象只能使用placement-newfoo::make_space()返回的内存中创建/构造, 因为是普通的构造,如

derived_from_foo z;                 // or
auto p = new derived_from_foo();

可能会导致意外的问题(如我最终发现的那样,内存损坏,取决于编译器)。所以我的问题是:如何编写/设计派生类

struct bar  // still abstract,since foo::job() is not provided
  : foo
{
    ...
    template<typename Derived,typename...Args>
    static Derived* create(Args&&...args)
    {
        return ::new(foo::make_space(sizeof(Derived)))
            Derived(std::forward<Args>(args)...);
    }
};

以某种方式构造bar 或从bar 派生的任何类型的对象,而不是通过bar::create()构造,则在(i)编译或(ii,不太理想)在运行时?

解决方法

您实际上可以以一定的价格执行它。

考虑此类:

  class A
  {
      public:
          class Tag
          {
              public:
                  Tag(const Tag&) = default;
                  Tag(Tag&&) = default;
              private:
                  Tag() {}
                  friend class A;
          };

          A(Tag,int a,char b) : a(a),b(b) {}
          int a;
          char b;

          template<typename T,typename ... Params>
          static T* make(Params&& ... params)
          {
              return new T(Tag(),std::forward<Params>(params)...);
          }
  };

它的构造函数需要一个Tag参数,但是您不能创建一个Tag,它有一个私有的构造函数。您可以从A派生,但是您也不能直接创建派生类的对象:它需要将Tag传递给其父构造函数,并且您不能创建它。

因此,创建A对象或派生类的对象的唯一方法是调用A::make


还有一种作弊的方法

class B : public A
{
    public:
        B(Tag t,double q) : A(t,42,'z'),q(q) {
           // cheating:
           B* other = new B(t,3.14);
        }
        double q;
};

如果这困扰您,您仍然可以在运行时通过将Tag设为不可重用std::unique_ptr来强制执行正确性。删除复制ctor,放入您在构造中设置的私有bool标志,并在移出时清除,然后在make内部对其进行检查。