2012-01-30 33 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