C ++获取对返回对象的引用

时间:2011-08-09 19:49:53

标签: c++ reference

我需要通过引用抓取一个对象,而我过去常常这样做:

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作为参考?

5 个答案:

答案 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_ptrunique_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_ptrstd::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;
};