2012-01-30 93 views
0
class X { 
    X(int, int); //constructor 
    void func(); 
} 

class Y { 
    public int func() { 
    X x(5,7); 
    // some other random operations. 
    x.func(); 
    } 
} 

现在,如果我必须基于一些条件初始化x,我该如何做?做以上的不美观的方式如何在C++中有条件地初始化一个对象

class Z { 
// only refer to x when mycond is true. 
    public int func(boolean mycond) { 
    if(mycond) 
    X x(5,7); 
    //same random operations; 
    if(mycond) 
     x.func(); 
    } 
} 

一种方法是:

class Z { 
    // only refer to x when mycond is true. 
    public int func(boolean mycond) { 
    if(mycond) { 
     X x(5,7); 
    //same random operations; 
     x.func(); 
    } 
    else { 
     //same random operations 
    } 
    } 
} 

我在寻找的东西更简单,我没有重复的代码。

+3

是否有任何理由不能在“随机操作”之后在条件内声明/初始化'x'? – Mankarse 2012-01-30 07:37:07

+2

你真的需要这个吗?做这些*“随机操作”*以任何方式依赖于'x'?如果是这样,那么你可能在那里有一些令人讨厌的副作用,你最好摆脱。也许你可以给我们一个随机操作的例子,或描述你的总体目标。 – 2012-01-30 07:44:23

+0

你可以看看'boost :: optional'。 – 2012-01-30 07:44:30

回答

0

你可以分解出的“随机行动”,类似这样的

if (my_cond) X x(5, 7); 
random_operations_factored_out(T& a, U& b, const W& c, ..); // all the references that you need 
if (my_cond) X.func(); 

很明显,你可以(应该?)封装方面比较好,我用传递通过引用一个例子的缘故。

另一种可能性是封装在一对构造函数和析构函数的逻辑,像

class X_caller{ 
private: 
    bool cond; 
    X x; 
public: 
    X_caller(bool cond, int param1, int param2):cond(cond){ 
     if (cond) {x = X(param1, param2);} 
    } 
    ~X_caller(){ 
     if (cond) x.func(); 
    } 
} 

现在,您将使用类似这样的

{ 
X_caller(my_cond, 5, 7); 
// all your operations 

} // at the end of the scope the destructor of X_caller calls x.func() only if my_cond was true 
    // but you "can't see" this function call if you don't know the body of X_caller, so be careful! 
    // You have to document this kind of behaviour otherwise it's too obscure for future maintenance. 

在任何情况下,你必须确保所有必须访问的资源(变量等)都可用于分解代码。

各种选择之间的平衡取决于代码的复杂性:总是尽量减少代码读者的潜在混淆。这可能来自长时间重复的代码,或来自“隐藏”的呼叫或许多其他来源,如果可能,您应该尽量减少它。

0

如何使用newpointer (*)

X *xPtr = 0; 
class Z 
{ 
    // only refer to xPtr when mycond is true.  
    public int func(boolean mycond) 
    { 
     if(mycond) 
     {   
      xPtr = new X(5,7);  
     } 

     //same random operations;     

     if(xPtr) 
     { 
      xPtr.func();  
     } 
    } 

    // and don't forget delete xPtr; 
} 

,看看是否上面的代码可以被重构为:

X *xPtr = 0; 
class Z 
{ 
    // only refer to xPtr when mycond is true.  
    public int func(boolean mycond) 
    { 
     //same random operations;     

     if(mycond) 
     {   
      xPtr = new X(5,7);  
      xPtr.func();  
     } 
    } 

    // and don't forget delete xPtr; 
} 
+1

如果您必须使用指针,那么使用自动指针,例如'std :: auto_ptr' – rve 2012-01-30 07:47:29

+0

这个解决方案适用于我。谢谢! – 2012-01-30 07:55:31

+0

“'public int'”是无效的C++。 – Johnsyweb 2012-01-30 08:30:38

1

显而易见的解决方案是使用一个指针,或自动指针:

class Z { 
public: 
    // only refer to x when mycond is true. 
    int func(boolean mycond) { 
    std::auto_ptr<X> px; 
    if(mycond) 
     px = new X(5,7); 
    //same random operations; 
    if (px.get() != 0) 
     px->func(); 
    } 
} 
+0

“'public int'”是无效的C++。 – Johnsyweb 2012-01-30 08:30:46

+0

@Johnsyweb:没错,我只是复制了OP的例子,并没有注意那部分。不过,这与问题无关。 – Miguel 2012-01-30 08:54:45

4

在你给出的例子中,它不是清除[R为什么你不能只是把它写为:

class Z { 
    // only refer to x when mycond is true. 
    public: 
    int func(bool mycond) { 
     //same random operations; 
     if(mycond) { 
      X x(5,7); 
      x.func(); 
     } 
    } 
}; 

但是,如果由于某种原因,这是不可取的(例如,如果X构造有一定的副作用,必须之前“一些随机操作”发生),那么你应该看看boost::optional

class Z { 
    // only refer to x when mycond is true. 
    public: 
    int func(bool mycond) { 
     boost::optional<X> x; 
     if (mycond) x = X(5,7); 
     //some random operations; 
     if (mycond) x->func(); 
    } 
}; 

如果你不想使用boost::optional出于某种原因,那么类似的效果可与union获得:

class Z { 
    // only refer to x when mycond is true. 
    public: 
    int func(bool mycond) { 
     union OptionalX { 
      OptionalX() {} 
      X value; 
     } x; 
     if (mycond) new (&x.value) X(5,7); 
     try { 
      //some random operations; 
      if (mycond) { 
       x.value.func(); 
       x.value.~X(); 
      } 
     } 
     catch (...) { if (mycond) x.value.~X(); } 
    } 
}; 

也就是说,这将导致名称引入到该名称仅有时具有含义的范围中。这是非常可疑的,你应该考虑使用不同的设计。

2

答案显然是把其他的随机操作在一个单独的 功能,让你的代码变成:

int 
func() 
{ 
    if (myCondition) { 
     X x(5, 7); 
     otherOperations(); 
     x.func(); 
    } else { 
     otherOperations(); 
    } 
} 

你或许应该这样做,无论如何,如果仅仅是为了使函数 可读性和可维护性。

0

您的要求只是不重复某些事情,您可以使用空对象模式。

class Base 
{ 
}; 
class X : public Base 
{ 
}; 
class NullX : public Base 
{ 
}; 

然后

int funX(boolean mycond) { 
    Base* p = NULL; 
    if (mycond) 
     p = new x(5,7); 
    else 
     p = new NullX; 
    //... some other 

    //if (mycond) 
    p->func(); 
} 

那么我们就可以删除第二个if语句。

,并进一步,如果我的条件是只用于控制X,那么funX将是:

int funX (Base& x) 
{ 
    //some other 
    x.func(); 
} 

和mycondtion将是另一个功能,

Base* getBase(int mycond) 
{ 
    if (mycond) 
    return new X(5, 7); 
    return new NullX; 
} 

那么函数将完全重构。

+0

最好不要引入内存泄漏。如果你使用指针,为什么还要引入一些奇怪的“空对象”? – 2012-01-30 11:35:51

+0

我只是想让funX只有一个运行流程。 – lyanbo 2012-01-30 14:16:45