2012-04-03 38 views
3

我有这样的事情:C++:引用和工厂

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

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

有写类似

D& d = make_D(); 
foo(d); 

(甚至foo(make_D()))的方法吗?我们的目标是将各种D定义和make_D()中的复杂性都包含进来,以便诸如foo()之类的函数和那些调用这些函数的函数不必担心。

+0

注意:'foo(D())'不会被编译(不在符合的编译器下,甚至VS会发出关于非标准行为的警告),因为临时的不能绑定到非const的l值引用。 – 2012-04-03 10:20:47

回答

5

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

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

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

const SmartPtr<D> make_D() 
{ 
    if(is_tuesday()) 
     return SmartPtr(new D1()); 
    return SmartPtr(new D2()); 
} 
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; 
} 
0

首先,我不太肯定我明白了。您列出的代码不是合法的 ,并且不会被编译。你确定它是不是:

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

和:

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

调用,或者是可变的? (可能不会,因为你没有传入任何 参数,并且在使用后丢弃该对象。)如果没有,那么你可以简单地返回对静态实例的引用。这是我使用的通常的 解决方案。否则,可以使用信封信封成语来使可复制对象 呈现多态,但它的工作位为 ,并且具有显着的运行时间开销,因为它通常要求 需要克隆每个副本的实际对象。