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

发布于 2024-11-28 12:00:38 字数 412 浏览 1 评论 0原文

我需要通过引用来获取一个对象,我曾经这样做过:

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 成为第二个示例中的引用?

I need to grab an object by reference and I used to do it like so:

MyObject& obj = FactoryThatGivesAnObject();
obj.MethodThatModifieObj();

No I need to do it based on a conditional:

MyObject obj;

// Need obj to be a reference to the returned values below
if( foo )
    obj = FactoryThatGivesAnObject();
else
    obj = OtherFactoryThatGivesAnObject();

obj.MethodThatModifiesObj();

How can I have obj be a reference in the second example?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

塔塔猫 2024-12-05 12:00:38

与指针不同,引用只能设置一次。很多时候,这是一个有用的功能,但这是它令人沮丧的一个方面。您只想设置一次引用,但可能是不同的东西。

你有两个选择。

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 - 一个简单的布尔值。随着事情的发展,您可能需要额外的标准来帮助确定要使用哪个工厂。
  • 工厂对象。您可能拥有工厂对象而不是工厂方法,在这种情况下,您需要将对这些对象的引用传递到您的方法中。

References, unlike pointers, can only be set once. This is a useful feature many times, but this is the one frustrating aspect about it. You only want to set the reference once, but possibly to different things.

You have two options.

1) Use the ternary operator

This is often the easiest, if you're only dealing with two factories, and a simple boolean to decide which to use:

MyObject& obj = ( foo
                  ? FactoryThatGivesAnObject();
                  : OtherFactoryThatGivesAnObject() );

However, if foo is more complicated, or if you have multiple factory options, the next option may be cleaner.

2) Use a factory method of your own

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);

Note that you may need to pass several parameters to your factory method:

  • selection criteria. Your example was just foo - a simple boolean. As things grow, you may need additional criteria to help determine which factory to use.
  • factory objects. You may have factory objects instead of factory methods, in which case you need to pass references to those objects into your method.
流心雨 2024-12-05 12:00:38

一种解决方案可能是使用三元运算符:

obj = foo ? FactoryThatGivesAnObject() : OtherFactoryThatGivesAnObject();

您也可以使用指针:

MyObject* pobj;
if( foo )
    pobj = &FactoryThatGivesAnObject();
else
    pobj = &OtherFactoryThatGivesAnObject();

One solution may be to use a ternary operator:

obj = foo ? FactoryThatGivesAnObject() : OtherFactoryThatGivesAnObject();

You could also use a pointer:

MyObject* pobj;
if( foo )
    pobj = &FactoryThatGivesAnObject();
else
    pobj = &OtherFactoryThatGivesAnObject();
素手挽清风 2024-12-05 12:00:38

你的第一句话就很可疑:

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); }

Your very first line is shady:

MyObject& obj = FactoryThatGivesAnObject();

How is that supposed to work? The factory method cannot return a reference to a temporary, so the only sensible reference it could return is to a dynamically created object - but now who is responsible for this object?

(Unless you are just returning a reference to an existing object, that is. But I'm assuming that your factory is genuinely creating new objects.)

This code is a memory-leak car crash; I don't see any way to write anything sensible like that. A far better way is to return the newly created object in a responsible container, e.g. a shared_ptr or a unique_ptr:

#include <memory>

std::unique_ptr<MyObject> FactoryFunction()
{
  return std::unique_ptr<MyObject>(new MyObject(3,5,7));
}

That way, if nobody picks up the factory product, or if an exception occurs, the dynamically allocated object will get properly disposed of.

This also makes it trivial to assign different pointers depending on a conditional:

std::unique_ptr<MyObject> x;

if (...)      { x = Factory1(); }
else if (...) { x = Factory2(a,b); }
else          { x = Factory3(argc, argv); }
你是暖光i 2024-12-05 12:00:38

如何让 obj 成为第二个示例中的引用?

你不能。参考文献是别名;您只能通过将它们指向某物来创建它们,并且一旦您指向它们,就无法重新分配它们。

您可能最好在这里使用 std::auto_ptrstd::unique_ptr 之类的东西。请注意,您的工厂需要返回 auto/unique_ptr 。如果您的工厂返回引用,我怀疑您可能会意外返回对未命名临时对象的引用(未定义的行为),但如果没有看到工厂的代码,就很难判断。

How can I have obj be a reference in the second example?

You can't. References are aliases; you can only create them by pointing them at something, and once you've pointed them, they cannot be reassigned.

You would probably be better off using something like a std::auto_ptr or std::unique_ptr here. Note that your factory would need to return the auto/unique_ptr though. If your factory is returning a reference I suspect you might be accidentially returning references to unnamed temporaries (unedefined behavior), but without seeing the factories' code it's difficult to tell.

淡看悲欢离合 2024-12-05 12:00:38

这是一个解决方案,从技术上讲,它不是工厂,但解决了同样的问题 - 在更改参数时提供新对象:

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;
};

Here's one solution which is not technically a factory, but solves the same problem -- providing new objects when you change parameters:

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;
};

This version has advantage that it does not pass around ownership to the object, but still you can create different kinds of objects with it. Two calls to get_obj_a() will cause problems though, it only works if you call get_obj_a() immediately before you need the object. Now the if statement can be put inside the factory function. Also here's another way to do it:

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;
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文