微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 C++ 中只公开类实例

如何解决在 C++ 中只公开类实例

我试图定义一个禁止显式实例化的类。 用户必须只能使用有限的一组实例。

代码方面,我目前正在做这样的事情:

class Obj
{
private:
  int _x;
  Obj(int x) : _x() {}

public:
  static const Obj obj1;
  static const Obj obj2;
};

const Obj Obj::obj1(1);
const Obj Obj::obj2(2);

int main()
{
  Obj o1 = Obj::obj1;
}

构造函数是私有的,类实例可通过 Obj::xxx 获得。

然而,通过这种方法,我不喜欢一个实例从另一个实例可见的事实。

(即我不希望 Obj::obj1.obj2.obj1 成为有效的语法)

是否有任何解决方法或更好的模式来避免这种行为?

解决方法

公共静态成员(函数或对象)总是能够在从该类的实例中查找时找到——因此避免它的唯一方法是不提供这些作为类型中的 static 成员您正在提供。

由于您要求保持 Obj 的构造函数私有,我们需要使用 friendship somewhere 以便外部主体可以提供这些对象并访问 {{ 1}} 的构造函数而不是 Obj 类型(这是允许链接的原因)。

出于这个原因,我建议使用辅助 Objclass 类型,以便它可以structed 以允许它调用 friend 的构造函数:

Obj

这也可以是一个包含 class ObjConstants; class Obj { // Note: friendship here so that ObjConstants can construct it friend ObjConstants; private: int _x; Obj(int x) : _x() {} }; class ObjConstants { public: static const Obj obj1; static const Obj obj2; }; const Obj ObjConstants::obj1(1); const Obj ObjConstants::obj2(2); int main() { Obj o1 = ObjConstants::obj1; } 工厂函数的类:

static

甚至只是一堆 class ObjConstants { public: static const Obj& getObj1(); static const Obj& getObj2(); }; 范围内的工厂函数,每个函数都单独添加:

namespace

当您为静态对象使用外部持有者(无论是类型还是函数)时,对象的每次访问都会返回与持有者不同的类型(在本例中为 const Obj& getObj1(); const Obj& getObj2(); class Obj { friend const Obj& getObj1(); friend const Obj& getObj2(); ... }; ),这会阻止链Obj


还值得注意的是,这种方法也适用于 obj1.obj2.obj1 对象。您不能在它自己的类的主体中定义 static constexpr 对象,因为此时该类是不完整的,例如:

static constexpr

因此,使用辅助持有人类型(无论是 class Foo { public: static inline constexpr auto foo = Foo{}; // Error: 'Foo' is incomplete! }; 还是 class)可以使定义在那时完成:

namespace

注意: 一般来说,我建议不要使用像这样具有外部链接的 class Foo { ... }; class FooConstants { public: static inline constexpr auto foo = Foo{...}; }; 对象,以避免静态初始化问题

,

您需要 Factory Pattern 的变体。这基本上是一个静态方法,可以访问您的私有构造函数,但规定了返回内容的条款。见下文:

class Obj
{
private:
  int _x;
  Obj(int x) : _x(x) {}
// Do the two lines below if you want,you'll catch more compiler errors that way
//  Obj(const Obj&) = delete; // Delete copy constructor
//  Obj& operator=(const Obj&) = delete; // Delete assignment operator

public:
  static Obj& getObj1();
  static Obj& getObj2();
};

Obj& Obj::getObj1()
{
    static Obj obj1{ 1 }; // Only initialized when getObj1() is called,and only once
    return obj1;
}

Obj& Obj::getObj2()
{
    static Obj obj2{ 2 }; // Only initialized when getObj2() is called,and only once
    return obj2;
}

int main()
{
  Obj& ref_o1 = Obj::getObj1();  // Requires a reference
  //Obj notref_o1 = Obj::getObj1();  // Fails to compile,not a reference!
  Obj& ref_o2 = Obj::getObj2();

  Obj& ref_other_o1 = Obj::getObj1(); // References the SAME object as ref_o1
}

你也可以让你的工厂接受一个参数来代替你想要的实例,如果你愿意,可以在那里保存你的对象的静态集合,尽管你可能会遇到需要给复制/分配/销毁朋友访问权限容器。但是如果你想要一个包含集,上面的应该是一个很好的蓝图。

我上面将分配放在静态方法(不是全局)中的方法也避免了人工编译器引用的 Static Initialization Order Fiasco 问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。