我正在进行模拟,它需要创建多个相似的模型。我的想法是有一个名为Model的类,并使用静态工厂方法来构建模型。例如; Model :: createTriangle 或 Model :: createFromFile 。我从之前的Java代码中接受了这个想法,并且正在寻找在C ++中实现它的方法。
这是我到目前为止所提出的:
#include <iostream>
class Object {
int id;
public:
void print() { std::cout << id << std::endl; }
static Object &createWithID(int id) {
Object *obj = new Object();
obj->id = id;
return *obj;
}
};
int main() {
Object obj = Object::createWithID(3);
obj.print();
return 0;
}
有关此问题的一些问题:
答案 0 :(得分:6)
只是为了记录,以下是这个程序在适当的C ++中的样子:
class Object
{
int id;
// private constructor, not for general use
explicit Object(int i) : id(i) { }
public:
static Object createWithID(int id)
{
return Object(id);
}
};
int main()
{
Object obj1 = Object::createWithID(1);
auto obj2 = Object::createWithID(2); // DRY
// return 0 is implied
}
这可能不是人们通常所说的工厂&#34;,因为工厂通常涉及一些动态类型选择。术语&#34;命名构造函数&#34;但有时会使用它来引用返回类实例的静态成员函数。
答案 1 :(得分:5)
您的代码当前包含内存泄漏:必须使用new
清除使用delete
创建的任何对象。 createWithID
方法最好不要使用new
,看起来像这样:
static Object createWithID(int id)
{
Object obj;
obj.id = id;
return obj;
}
这似乎需要额外的对象副本,但实际上return value optimization通常会导致此副本被优化掉。
答案 2 :(得分:2)
这是一种被接受且干净的制作物品的方法吗?
(不幸的是)它被接受但它不干净。
只使用构造函数而不是工厂函数。
这就是他们的目标。
返回的引用是否始终确保正确删除对象?
该引用无关紧要,除非误导该函数的用户。
在你的例子中,引用显然误导了你不破坏动态分配的对象,而只是复制它。
最好返回智能指针。
但正如已经提到的,放弃工厂职能的想法更好。
他们在这里完全没必要。
如果没有指针,有没有办法做到这一点?
不,不是,如果&#34;这&#34;指动态分配,但您可以而且应该使用构造函数而不是工厂函数。
示例:
#include <iostream>
namespace better {
using std::ostream;
class Object
{
public:
auto id() const -> int { return id_; }
explicit Object( int const id): id_( id ) {}
private:
int id_;
};
auto operator<<( ostream& stream, Object const& o )
-> ostream&
{ return (stream << o.id()); }
} // namespace better
auto main()
-> int
{
using namespace std;
cout << better::Object( 3 ) << endl;
}
答案 3 :(得分:1)
这是创建对象的绝对可怕方法。每次调用createWithID
时,都会在免费商店上构建一个永远无法销毁的新Object
。
您应该将createWithID
重写为:
static Object createWithID(int id) {
Object obj;
obj.id = id;
return obj;
}
或者更好的是,您可以为Object
个对象提供构造函数。
如果要启用多态对象,则应使用类似wheels::value_ptr的内容。
答案 4 :(得分:1)
通过调用Object *obj = new Object();
,您可以在堆上分配内存。在该语句后面的行中,您确实返回对该对象的引用。到目前为止,这么好,但你永远不会删除你创建的对象以实际释放内存。通过多次调用该函数,您将在内存泄漏中运行。
有两种可能的解决方法:
static Object createWithID(int id);
将返回您创建的Object的副本,因此使用
Object tmp;
tmp.id = id;
使用c ++ 11智能指针让它们处理内存。
#include <memory>
static std::unique_ptr<Object> createWithID(int id)
{
std::unique_ptr<Object> tmp(new Object());
tmp->id = id;
return std::move(tmp);
}
答案 5 :(得分:1)
除非您使用多态,否则您的工厂函数没有理由返回任何类型的指针,它们只能按值返回对象。任何现代编译器都会执行return value optimization,因此没有副本。
如果您正在接受&#34;接受并清洁&#34;然后,这听起来很基于意见,并取决于如何使用这个类,但我要做的是保持Model
的定义尽可能小。只包含正常使用所需的最少构造函数所需的工作:
namespace Simulation {
class Model {
private:
int id_;
public:
explicit Model(int id) : id_(id) {}
// minimum required to do the job...
};
}
然后,我将定义函数以分别创建各种风格的Model
。例如,作为名称空间中的非成员,非朋友函数:
namespace Simulation {
Model createTriangle(int id) {
Model model(id);
// do whatever you need to do to make it a triangle...
return model;
}
Model createSquare(int id) {
Model model(id);
// do whatever you need to do to make it a square...
return model;
}
}
这样,如果您发现需要另一种Model
,则不需要更改Model
课程。如果需要,您的创建函数甚至可以分布在多个文件中,或者成为Builder或Factory类的一部分。用法如下:
int main() {
Simulation::Model m1(0);
Simulation::Model m2 = Simulation::createTriangle(1);
Simulation::Model m3 = Simulation::createSquare(2);
}