2012-01-07 19 views
-2

我尋找用於C++對象的局部重新初始化的最佳模式對象。部分重新初始化++通過構造

對於部分重新初始化,我的意思是某些成員(代碼示例中的step_param)需要保留其值,並且其他成員(代碼示例中的value)被重新初始化。

重要的一點:應避免執行與構造函數基本相同的init()或reset()成員函數的膨脹和冗餘。

到目前爲止,我有以下解決方案:

namespace reinit_example 
{ 
    struct reinit_t {} reinit; 

    struct stepper_t 
    { 
     int step_param; // keep parameter 
     int value; 

     stepper_t() 
      : step_param(1) 
      , value(step_param) 
     {} 
     stepper_t(const stepper_t & c, reinit_t) 
      : step_param(c.step_param) 
      , value(step_param) 
     {} 

     void step() 
     { 
      value += step_param; 
     } 

    }; 

    void use_cases_1() 
    { 
     stepper_t c; 
     // use c 
     c.step(); 
     // and later reinit 
     c = stepper_t(c,reinit); 
    } 
} // namespace 

還應該有繼承和組合工作得很好:

namespace reinit_example 
{ 
    struct stepper_2_t : public stepper_t 
    { 
     int step_param_2; // keep parameter 
     int value_2; 

    public: 
     stepper_2_t() 
      : step_param_2(0) 
      , value_2(step_param_2) 
     {} 

     stepper_2_t(const stepper_2_t & cc, reinit_t) 
      : stepper_t(cc) 
      , step_param_2(cc.step_param_2) 
      , value_2(step_param+2) 
     {} 
     void step() 
     { 
      stepper_t::step(); 
      value_2 += value + step_param_2; 
     } 
    }; 

    struct stepper_comp_t 
    { 
     stepper_t c; 
     stepper_2_t cc; 
    public: 
     stepper_comp_t() 
     {} 
     stepper_comp_t(const stepper_comp_t & d, reinit_t) 
      : c(d.c,reinit) 
      , cc(d.cc,reinit) 
     {} 
     void step() 
     { 
      c.step(); 
      cc.step(); 
     } 
    }; 

    void use_cases_2() 
    { 
     stepper_2_t cc; 
     // use cc, change config 
     cc.step(); 
     // maybe change config 
     cc.step_param = 2; 
     // reinit 
     cc = stepper_2_t(cc,reinit); 

     stepper_comp_t d; 
     d = stepper_comp_t(d,reinit); 
    } 
} // namespace 

C++ 11的非靜態成員初始化使它更簡單:

#if __has_feature(cxx_nonstatic_member_init) 
namespace reinit_example 
{ 
    struct stepper_11_t 
    { 
     int step_param = 0 ; // keep value 
     int value = step_param; 

     stepper_11_t() 
     {} 

     stepper_11_t(const stepper_11_t & c11, reinit_t) 
      : step_param(c11.step_param) 
     {} 
    }; 

    void use_cases_3() 
    { 
     stepper_11_t c11; 
     c11 = stepper_11_t(c11,reinit); 
    } 

} // namespace 
#endif 

來進行測試:

傑裏·科芬提出的
int main() 
{ 
    reinit_example::use_cases_1(); 
    reinit_example::use_cases_2(); 
#if __has_feature(cxx_nonstatic_member_init) 
    reinit_example::use_cases_3(); 
#endif 
} 

解決方案:參數被移動到一個單獨的結構,它被傳遞到構造函數來重新初始化。

namespace reinit_example 
{ 

    struct stepper_config_t 
    { 
     struct config_t 
     { 
      config_t() 
       : step_param(1) 
      {} 
      int step_param; 
      int other_param; 
     }; 
     config_t config; 
     int value; 

     stepper_config_t() 
      : value(config.step_param) 
     {} 

     stepper_config_t(const config_t & c) 
      : config(c) 
      , value(c.step_param) 
     {} 

     void step() 
     { 
      value += config.step_param; 
     } 

    }; 

    void use_cases_4() 
    { 
     stepper_config_t c; 
     // use c 
     // and later reinit 
     c = stepper_config_t(c.config); 
    } 
} // namespace 
+6

【什麼問題,你實際上是試圖解決?(http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)這聽起來像一個大量的工作做一些事情,因爲C++對象在其生命週期中僅被初始化(構造)一次,所以它確實沒有什麼意義(「部分重新初始化」?)。 – 2012-01-07 22:01:27

+0

你的回答非常快。你真的想過嗎? – hpc 2012-01-07 22:06:10

+14

這不是一個答案,它是一個評論,要求澄清。是的,我確實考慮過這個問題,並得出這樣的結論:這可能不是解決您嘗試解決的任何問題的正確方法。這就是爲什麼我問你的實際問題是什麼。 [你試圖做X,並且你想到解決方案Y.所以你問的是解決方案Y,甚至沒有提到X.問題是,可能有更好的解決方案,但除非你知道,否則我們無法知道描述X是什麼。](http://www.perlmonks.org/index.pl?node_id=542341) – 2012-01-07 22:07:34

回答

0

我相信你應該尋找完全不同的設計模式。

例如,「守護者」成員應該形成一個功能齊全的類,而其他不想保留的成員將被視爲該類的上下文(將是另一個類,用於在第一類上做一些操作)。

這是一種類似於flyweight design pattern

+0

感謝您的回答。 _「門將」成員應該組成一個全功能的班級:這與Jerry Coffin的建議解決方案相對應。我把它寫在stepper_config_t類中。使用上下文類意味着每個類都有一個額外的類和更多的指向(配置類需要從上下文類訪問)。使用reinit構造函數的解決方案的優點是不需要輔助類。 – hpc 2012-01-11 01:50:10

+0

嗯,是的,沒有。 「reinit構造函數」可能會減少您需要編寫的代碼量,但我相信這會使代碼長期運行(維護,可擴展性等)變得複雜。我相信「兩班」解決方案更清潔,雖然它更多的工作。 – 2012-01-11 08:14:20

+0

但正如我所說,這應該用於「門將」成員組成一個全功能的類。在你的例子中,「守護者」只是一個整數,因爲沒有任何(合理的)操作可以完成整個類的生成(get/set除外)。爲此,我建議推薦就地構造函數Basile Starynkevitvc,因爲它不涉及複製。 – 2012-01-11 08:14:31