首页 > 解决方案 > 如何始终通过某种方法强制执行该构造?

问题描述

我有一些第三方抽象基类

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

我无法改变。类型的对象foo(和所有派生类)只能使用placement-new创建/构造到由返回的内存中foo::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 派生的任何类型barbar::create()的对象在(i)编译或(ii,不太理想)在运行时失败?

标签: c++polymorphismc++14object-construction

解决方案


实际上,您可以以一定的代价强制执行它。

考虑这个类:

  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参数,但你不能制作 a Tag,它有一个私有构造函数。您可以从 派生A,但也不能直接创建派生类的对象:它需要将 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不可重用 à la在运行时强制执行正确性std::unique_ptr。删除复制 ctor,放入您在构造时设置并在移出时清除的私有 bool 标志,然后在内部检查它make


推荐阅读