gpt4 book ai didi

c++ - 仅在 Manager 类中创建对象

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:02:16 25 4
gpt4 key购买 nike

我想创建一个管理器类来管理所有已创建的一种类型的对象。自然这个类也应该创建这些对象。因此,不允许客户端自己创建对象,而必须始终使用管理器类来创建对象。此外,允许客户定义他自己的类,这些类将由一个管理器管理。

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)的,而管理器仍然可以毫无问题地工作。但是客户端将能够在管理器类不在场的情况下创建这些类的实例,从而导致框架的不良行为/资源管理。

有没有办法克服这个问题?

最佳答案

这种类型的经理通常是一种糟糕的模式。以下代码示例说明了原因。

这与说所有析构函数都应该是虚函数的问题是同一个问题。我使用管理器创建一个 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 容器本身并不是线程安全的。

关于c++ - 仅在 Manager 类中创建对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25834300/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com