我需要通过引用抓取一个对象,而我过去常常这样做:
MyObject& obj = FactoryThatGivesAnObject();
obj.MethodThatModifieObj();
不,我需要根据条件来做这件事:
MyObject obj;
// Need obj to be a reference to the returned values below
if( foo )
obj = FactoryThatGivesAnObject();
else
obj = OtherFactoryThatGivesAnObject();
obj.MethodThatModifiesObj();
如何在第二个例子中将obj作为参考?
答案 0 :(得分:5)
与指针不同,引用只能设置一次。这是一个有用的功能很多次,但这是一个令人沮丧的方面。您只想设置一次引用,但可能设置不同的引用。
您有两种选择。
1)使用三元运算符
这通常是最简单的,如果你只处理两个工厂,并使用一个简单的布尔值来决定使用哪个:
MyObject& obj = ( foo
? FactoryThatGivesAnObject();
: OtherFactoryThatGivesAnObject() );
但是,如果foo
更复杂,或者您有多个工厂选项,则下一个选项可能更清晰。
2)使用您自己的工厂方法
MyObject& get_an_object(const int state) // or whatever parameters you need
{
switch(state)
{
case USE_LEGACY_FACTORY: return FactoryThatGivesAnObject();
case USE_FOO_FACTORY: return OtherFactoryThatGivesAnObject();
case DO_SOMETHING_ELSE: return YetAnotherObjectFactory();
}
throw std::runtime_error("Bad Factory Selector");
}
// usage is simpler now
MyObject& obj = get_an_object(foo);
请注意,您可能需要将几个参数传递给工厂方法:
foo
- 一个简单的布尔值。随着事情的发展,您可能需要其他标准来帮助确定要使用的工厂。答案 1 :(得分:3)
一种解决方案可能是使用三元运算符:
obj = foo ? FactoryThatGivesAnObject() : OtherFactoryThatGivesAnObject();
您也可以使用指针:
MyObject* pobj;
if( foo )
pobj = &FactoryThatGivesAnObject();
else
pobj = &OtherFactoryThatGivesAnObject();
答案 2 :(得分:2)
你的第一行是阴暗的:
MyObject& obj = FactoryThatGivesAnObject();
这应该如何运作?工厂方法不能返回对临时的引用,因此它可以返回的唯一明智的引用是动态创建的对象 - 但现在谁负责这个对象?
(除非您只是返回对现有对象的引用,否则。但我假设您的工厂正在创建新对象。)
此代码是内存泄漏的车祸;我认为没有办法写任何合理的东西。更好的方法是在负责的容器中返回新创建的对象,例如shared_ptr
或unique_ptr
:
#include <memory>
std::unique_ptr<MyObject> FactoryFunction()
{
return std::unique_ptr<MyObject>(new MyObject(3,5,7));
}
这样,如果没有人拿起工厂产品,或者发生异常,动态分配的对象将被妥善处理。
这也使得根据条件分配不同的指针变得微不足道了:
std::unique_ptr<MyObject> x;
if (...) { x = Factory1(); }
else if (...) { x = Factory2(a,b); }
else { x = Factory3(argc, argv); }
答案 3 :(得分:1)
如何在第二个例子中将obj作为参考?
你做不到。参考文献是别名;你只能通过将它们指向某个东西来创建它们,一旦你指出它们,它们就不能被重新分配。
在这里使用像std::auto_ptr
或std::unique_ptr
这样的东西可能会更好。请注意,您的工厂需要返回auto / unique_ptr。如果你的工厂正在返回一个引用,我怀疑你可能会意外地返回对未命名临时工具的引用(未定义的行为),但是如果没有看到工厂的代码就很难说了。
答案 4 :(得分:0)
这是一个技术上不是工厂的解决方案,但解决了同样的问题 - 在更改参数时提供新对象:
struct A
{
int a;
float x;
int c;
};
class ObjectCollection
{
public:
ObjectCollection() { m_a.c = 10; }
A &get_obj_a(int a, float x)
{
m_a.a = a;
m_a.x = x;
return m_a;
}
private:
A m_a;
};
此版本的优点是它不会将所有权传递给对象,但您仍然可以使用它创建不同类型的对象。两次调用get_obj_a()会导致问题,只有在需要对象之前立即调用get_obj_a()时才会有效。现在if语句可以放在工厂函数中。这也是另一种方法:
class DerivedFactory
{
public:
DerivedFactory(ObjectCollection1 &c, ObjectCollection2 &c2) : c(c),c2(c2) { }
Base &get_obj_a_or_b(bool b) {
if (b) return c.get_obj_a(10,11.0);
else return c2.get_obj_b(20.0,13.0);
}
private:
ObjectCollection1 &c;
ObjectCollection2 &c2;
};