具有复杂构造函数的对象的c ++通用构建器方法

c++ generic builder method for object with complex constructor

我目前正在编写一个用于在场景中放置对象的小型通用库。对象的排列应根据对象内容的边界框来决定。 class 目前看起来像这样:

template<class T>
class Object {
  public:
    Object() = default;
    Object(const T& content, const Rect& bounding_box)
        : _content(content)
        , _bounding_box(bounding_box) {}
  private:
    T    _content;
    Rect _bounding_box;
};

现在,要构造对象,我们需要知道边界框。当然,它取决于内容的类型 T,计算起来可能相当复杂(即文本)。

我的想法是用户应该提供自己的 Measurer 来为他自己的内容执行此计算。然后可以通过以下方式创建一个对象:

template <class T, class Measurer>
Object create_label(const T& value, Measurer op)
{
    return Object(value, op(value));
}

是否应该将此方法以某种方式纳入 Object class(类似于政策)?我在想类似于 STL 中分配器的东西。是否有针对此类问题的通用设计模式,您将如何编写这样的 class?

另外,构造函数Object(const T& content, const Rect& bounding_box)是否应该标记为protected,以便用户指向create_label方法?

我想你想看看静态成员函数。这种类型的方法不需要(或没有)要操作的对象,因此它更像是一个全局函数,但它具有像 class 方法一样的范围和可见性。

诸如 createLabel 之类的工厂方法通常在 class 中声明如下:

class Object {
  public:
    static Object createLabel(...);     
}

现在因为这是一个静态方法你可以直接调用它而不需要实例:

Object O=Object.createLabel(...);

如果您想遵循此策略,那么您的构造函数应该是私有的或受保护的,以阻止 class 用户直接实例化它们。 (顺便说一句,这同样适用于像你这样的模板化 classes)

您可以使用多种其他策略来解决您的特定问题,这些策略可能更方便,具体取决于您的情况:

  • 定义一个名为getMeasurer的抽象方法,该方法有待定义 对于每个 Object subclass - 这似乎更多地绑定了 Measurer 在代码和语义上都与 subclass 紧密相关。
  • 在 class/one 方法上使用部分模板规范(这是 如果你对 c++ 不是很熟悉的话,这是相当技术性的)
  • 您可以使所有对象的构造函数的签名明确包含 测量器(而不是边界框级别)

编辑:应 OP 的要求,关于部分模板解决方案的一些想法: 最直接的方法是在模板定义中简单地声明一个函数,就像这样

template<class T>
class Object {
   .....
   private:
      BoundingBox measureMe();
}

现在因为没有为 measureMe 提供*定义&(上面是一个 声明)任何实例化的 Object 实例都将导致链接器错误,因为没有定义 MeasureMe() .

但是您为特定类型提供特定实现,因此您可以包含各种特定类型的定义:

BoundingBox Object<MyThing1>::measureMe()
{
   ...  calculatethe size of a MyThing1
}


BoundingBox Object<MyThing2>::measureMe()
{
   ...  calculate  the size of a MyThing2
}

现在,如果您尝试实例化一个您尚未为其定义测量值的对象类型,您仍然会收到错误消息;但已知类型可以按您的意愿工作。

请记住,您仍然可以定义此函数的通用模板版本,如果没有更具体的版本可用,这可能对您有用,如果您的大多数情况使用相同的逻辑但有一些边缘异常。

为什么不添加另一个采用测量器的构造函数?

template<class T>
class Object {
  public:
    Object() = default;
    Object(const T& content, const Rect& bounding_box)
        : _content(content)
        , _bounding_box(bounding_box) {}
    template<class Measurer>
    Object(const T& content, Measurer op) : _content(content), _bounding_box(op(content)){}
  private:
    T    _content;
    Rect _bounding_box;
};