我想创建一个管理器类,它将管理一种类型的所有创建对象。当然这个类也应该创建这些对象。因此,客户端不允许自己创建对象,但必须始终使用manager类来完成。 此外,客户端可以定义自己的类,这些类将由一个Manager管理。
template<class Type>
class Manager{
//...
Type* createInstance(){
Type* ptr = new Type();
//do sommething
return ptr;
}
};
问题是:如何仅将实例的创建限制为管理器类?
一种可能性是将构造函数声明为private,将Manager类声明为友元类:
class A{
friend class Manager<A>;
private:
A(){}
~A(){}
};
由于允许客户端定义自己的类,因此他可以将构造函数声明为public,并且管理器仍然可以正常工作。但是客户端能够创建这些类的实例,而没有经理类见证它,导致框架的不良行为/资源管理。
有没有办法克服这个问题?
答案 0 :(得分:2)
这类经理通常是一个糟糕的模式。以下代码示例说明了原因。
与所有析构函数都应该是虚拟的问题相同。我使用Manager创建一个B,它派生自A,将对象分配给A *指针。如果它被摧毁,它会通过Manager :: destroy(),因为它是通过Manager :: make()
创建的,所以它可能不会很好地结束#include <iostream>
using namespace std;
template<class Type>
class Manager
{
public:
Manager(char *type)
{
mytype = type;
}
Type *make()
{
Type *ptr = new Type();
cout << "in Manager<" << mytype << ">::make() ptr->mytype is " << ptr->mytype << endl;
return ptr;
}
void destroy(Type *ptr)
{
cout << "in Manager<" << mytype << ">::destroy() ptr->mytype is " << ptr->mytype << endl;
delete ptr;
}
private:
char *mytype;
};
class A
{
friend class Manager<A>;
protected:
A()
{
mytype = "A";
cout << "in A()" << endl;
}
virtual ~A()
{
cout << "in ~A() mytype is " << mytype << endl;
}
char *mytype;
};
class B : public A
{
friend class Manager<B>;
protected:
B()
{
mytype = "B";
cout << "in B()" << endl;
}
virtual ~B()
{
cout << "in ~B() mytype is " << mytype << endl;
}
};
int main()
{
Manager<A> ma("A");
Manager<B> mb("B");
B *b = mb.make();
A *a = b;
ma.destroy(a); // This line calls Manager<A>::destroy. It should call Manager<B>::destroy.
return 0;
}
产生以下输出:
in A()
in B()
in Manager<B>::make() ptr->mytype is B
in Manager<A>::destroy() ptr->mytype is B -- Oops - wrong destroy.
in ~B() mytype is B
in ~A() mytype is B
这反过来意味着你不能使用继承来实现它的全部功能,这实际上首先违背了使用OO语言的目的。
根据您认为需要经理的原因,可能有更好的解决方案。
如果它用于内存管理(不太可能是原始代码段),覆盖new和delete值得一看。
如果它是为了跟踪所有用于处理目的的实例(例如游戏中每个游戏滴答更新的对象)那么虽然它有点精神换档,但更好的解决方案是集成管理器进入类本身,作为一组静态成员函数和变量。这类经理几乎总是单身,所以让他们成为静态成员/函数会让你在语义上到达同一个地方。
所以你可能有:
static set<A *> s_collection;
static void Heartbeat() // in class A
{
// lock s_collection here
for (auto it = s_collection.begin, end = s_collection.end() it != end; ++it)
{
// process *it
}
// unlock s_collection here
}
然后在A :: A()期间将其插入到s_collection中,同样在A ::〜A()期间将其删除。
如果您已经多线程,请小心使用合适的同步原语,因为大多数stl容器本身并不是线程安全的。
答案 1 :(得分:1)
您可以使用密钥模式的某些变体来实现此目的: