如何解决在 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::obj1.obj2.obj1
成为有效的语法)
是否有任何解决方法或更好的模式来避免这种行为?
解决方法
公共静态成员(函数或对象)总是能够在从该类的实例中查找时找到——因此避免它的唯一方法是不提供这些作为类型中的 static
成员您正在提供。
由于您要求保持 Obj
的构造函数私有,我们需要使用 friend
ship somewhere 以便外部主体可以提供这些对象并访问 {{ 1}} 的构造函数而不是 Obj
类型(这是允许链接的原因)。
出于这个原因,我建议使用辅助 Obj
或 class
类型,以便它可以struct
ed 以允许它调用 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 举报,一经查实,本站将立刻删除。