C ++:引用和工厂

时间:2012-04-03 07:45:42

标签: c++ c++11

我有这样的事情:

struct D {
    virtual void operator() {...};
}
struct D1 : public D {
    virtual void operator() {...};
}
struct D2 : public D {
    virtual void operator() {...};
}

void foo(D &d) {...};

所以这很好,很好地控制了我D的生命周期:

foo(D());
foo(D1());
foo(D2());

但是我在多个地方选择我的D变种,所以我想要一个简单的工厂:

const D& make_D()
{
    // BAD, returning reference to temporary
    if(is_tuesday())
        return D1();
    return D2();
}

我可以返回一个对象,而不是返回对临时的引用,然后切换到基类。或者,我可以从我的工厂返回一个指针,但客户端必须删除它。其他更复杂的解决方案也会给客户带来更多负担。

有没有办法写出像

这样的东西
D& d = make_D();
foo(d);

(甚至foo(make_D()))?目标是将复杂性包含在各种D定义和make_D()中,以便像foo()这样的函数和调用这些函数的函数不必担心它。

3 个答案:

答案 0 :(得分:5)

通常的方法是返回指针或智能指针。

使用指针的缺点是让用户管理其内存。

如果你返回一个智能指针,这不再是一个问题。

const SmartPtr<D> make_D()
{
    if(is_tuesday())
        return SmartPtr(new D1());
    return SmartPtr(new D2());
}

答案 1 :(得分:5)

不幸的是,这是不可能的。

通常,我所做的就是使用std::unique_ptr(有时std::shared_ptr,当无法使用std::unique_ptr时):

typedef std::unique_ptr< D > Dptr;
Dptr make_D()
{
    Dptr p( nulptr );

    if(is_tuesday())
        p.reset( new D1 );
    else
        p.reset( new D2 );

    return p;
}

答案 2 :(得分:0)

首先,我不太清楚我的理解。您列出的代码不是 合法,不会编译。你确定它不是:

struct D
{
    virtual void operator()() const { /* ... */ }
};

void foo( D const& d ) { /* ... */ }

调用,还是可变的? (大概不是,因为你没有通过任何 参数,你在使用后丢弃对象。)如果没有,那么你 可以简单地返回对静态实例的引用。这是通常的 我用的解决方案。否则,可以制作可复制对象 使用字母包络成语,表现多态,但它有点 工作,并且具有显着的运行时开销,因为它通常 需要克隆每个副本的实际对象。