这是一个Unique类,用于创建唯一的对象。对象是通过工厂方法Unique::Get创建的,并通过传递给此方法的值来唯一。该方法检查唯一对象集合Unique::cache中是否存在带有该值(键)的对象,如果不存在,则创建一个新对象并将其插入到该对象集中。

我希望此类仅对用户有用。具体来说,用户不应通过调用Get方法来复制此类的对象或创建对象。为此,我将构造函数和赋值运算符声明为私有(private)。但是当我这样做时,我不能在类本身内使用std::set::emplace,因为构造函数是私有(private)的。

可能的解决方案是将std::set类声明为好友,但这将使用户也可以将此容器与我的类一起使用。这可能是有害的。

有没有更好的办法?

#include <set>
#include <iostream>
#include <iomanip>

class Unique {
public:
  // user accessible methods
  static const Unique &Get(int key);
  bool operator==(const Unique &other) const {
    return this == &other;
  }
private:
  // user inaccessible methods
  Unique(int key) : key_(key) {}
  Unique(const Unique &) = delete;
  Unique &operator=(const Unique &) = delete;
  int key_;
private:
  // cache related stuff
  struct Identity {
    Identity(int key) : key_(key) {}
    int key_;
  };
  struct Compare {
    struct is_transparent {};
    bool operator()(const Identity &lhs, const Unique &rhs) const {
      return lhs.key_ < rhs.key_;
    }
    bool operator()(const Unique &lhs, const Identity &rhs) const {
      return lhs.key_ < rhs.key_;
    }
    bool operator()(const Unique &lhs, const Unique &rhs) const {
      return lhs.key_ < rhs.key_;
    }
  };
  static std::set<Unique, Compare> cache;
};

std::set<Unique, Unique::Compare> Unique::cache;

const Unique &Unique::Get(int key) {
  Identity identity(key);
  auto it = cache.find(identity);
  if (it == cache.end()) {
    it = cache.emplace(key).first;
  }
  return *it;
}

int main() {
  const Unique &c1 = Unique::Get(1);
  const Unique &c2 = Unique::Get(1);
  std::cout << std::boolalpha << (c1 == c2) << std::endl;
}

最佳答案

除通过“官方 channel ”外,有几种防止直接构造类实例的常用技术。

这是其中最简单的一个:创建必须使用工厂方法构造的类的示例,但该类具有公共(public)构造函数:

头文件:

class Object {

    class private_inner {};

public:

    Object(const private_inner &);

    static Object factory();
};

您的实现类;
static Object::private_inner inner;

Object Object::factory()
{
    return Object(inner);
}

构造函数需要对私有(private)类成员的引用。即使构造函数是公共(public)的,它也不可用,因为私有(private)类成员不可访问。

同时,factory()本身没有问题。

我确定您可以使该示例适合您的类层次结构。请注意,您的工厂可以毫无问题地在C++库容器中调用emplace(),因为您的工厂将拥有对私有(private)类的完全访问权限,并将其传递给容器的方法。

10-07 13:35
查看更多