Re: [問題] 類別的傳遞

看板C_and_CPP作者 (最愛朴素妍)時間13年前 (2010/09/07 01:39), 編輯推噓2(207)
留言9則, 4人參與, 最新討論串2/2 (看更多)
※ 引述《OkeyBun (OK繃)》之銘言: : ( *[1m *[m 為色碼,可以按 Ctrl+V 預覽會顯示的顏色 ) : ( 未必需要依照此格式,文章條理清楚即可 ) : 遇到的問題: (題意請描述清楚) : 為了寫一個處理大量浮動數據的程式而定義了幾個類別型態 : 主要分為讀檔用和輸出用兩種 : 為了將來擴充和整合上的方便 : 想要把讀檔功能完全用讀檔類別內的成員函數搞定 : 也就是在 main() 裡面寫入 input::read(); 就讀檔完畢 : 問題是...讀檔函式使用到的資料本身就是類別陣列 : 希望讀入後的數據能夠在 main() 裡面提取出來做處理運算 : 請問...這有辦法在不從外部傳入指標或參照的狀況下完成嗎?? : (因為類別陣列的大小是浮動的 在讀檔過程中才能得到決定大小的資訊) : 補充說明: : 目前架構長這樣... : class orbital : { : public: : static int num_of_stste; : int atom_id; : double *energy; : double *int_s, *int_py, *int_pz, *int_px, *int_dxy... : orbital() : { : energy=new double[this->num_of_stste]; : int_s=new double[this->num_of_stste]; <────┐ : ... ... | : }//初始化參數 | : | : static void read(void); | : }; | 從上面的架構看來你把read放在這邊是為了能夠改變 num_of_state 這個「類別成員」來藉以改變生成的orbital物件的大小, 因為要定 義「物件陣列」的話, 該類別必須要有default ctor, 使得你產生了 這樣的設計. 很明顯這裡不需要靜態變數, energy、int_s 指向的記憶體大小應該 由 ctor 的參數來決定: explicit orbital::orbital( int num_of_state ); 不需要提供預設建構子, 你只需要再寫一個拷貝建構子即可 : orbital::orbital( orbital const &o ); 然後這裡如果想要讀檔之後回傳, 回傳的當然不能是區域的陣列, 為 讓回傳的物件存活時間更長, 你需要動態記憶體配置再回傳指標, 或 是回傳一個STL容器, 動態記憶體配置可以使用allocator類別幫你完 成, 只不過這過程會比較繁瑣, 交給現成的容器類別會輕鬆很多. : | : void orbital::read(void){ //瘋狂讀檔區 | : | : ifstream ifile(filename,ios::in); | : ... ... | : ifile>>orbital::num_of_state; //得到類別成員的數列大小來配置動態記憶體 : ifile>>data_num; //得到類別陣列大小 data_num : ... ... : orbital data[data_num]; //建立類別陣列 既然你要讓外部的函式使用到這塊記憶體, 常見的方式就是「回傳」 它, 而且這類回傳的動作就像是憑空產生東西出來, 所以命名用 create, 比較合乎語意, 另外因為這個函式不必要跟orbital糾纏在 一起, 我會比較習慣把他放在另一個類別裡 : struct OrbitalCreator { vector<orbital>* create(); }; 上面之所以回傳指標, 是為了避免多餘的拷貝動作拖慢程式速度 註(9/7):在C++0x中, 暫時物件的拷貝實際上即是內部資料的擁 有權轉移, 所以你可以把以上的介面修改成 : vector<orbital> create(); : for(i...){for(j...){ifile>>data[i].orbit_s[j]>>data[i].orbit_p[j]....}} : ... ...//進食數據迴圈 然後看看新的函式主體長怎樣 : ifstream ifile(filename,ios::in); //... int num_of_state; ifile >> num_of_state; int data_num; ifile >> data_num; //--------------------------------------------------------- vector<orbital> *p = new vector<orbital>( data_num, orbital(num_of_state) ); vector<orbital> &data = *p; // 這裡的程式碼都不用改 // 進食數據 return p; //--------------------------------------------------------- 註(9/7):在C++0x中, 你可以「預借」暫時物件, 對其修改再回傳 , 所以針對第二個介面, 虛線框住的地方也有第二種版本的寫法 : vector<orbital> &&data = vector<orbital>( data_num, orbital(num_of_state) ); // 這邊程式碼都不用改 // 進食數據 return std::move( data ); 註(9/7):因為一旦為了暫時物件取「別名」, 編譯器便會把它當作 區域物件看待, 為了保留「擁有權轉移」這個性質, 回傳時使用 std::move. : 簡而言之... 本來想在 main()裡建立orbital物件再傳到 orbital::read() 裡接收資料 : 但參數初始化的陣列長度 num_of_stste 和類別陣列大小data_num : 都是在讀檔的時候才知道 : 所以才會選擇把物件建立在 orbital::read() 內 : 但要傳回到 main() 裡與其他資料做合併計算就不得其門了... 類別的設計是非常重要的, 因為這會影響到你未來擴充程式的難 易度, 千萬不可以為了方便而妥協. -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.121.197.115 ※ 編輯: loveme00835 來自: 140.121.197.115 (09/07 01:47)

09/07 04:42, , 1F
C++0x 以後可以直接回傳 value,因為 vector 有實作
09/07 04:42, 1F

09/07 04:43, , 2F
move constructor,幾乎只是 pointer 切換一下再把值歸零
09/07 04:43, 2F

09/07 04:43, , 3F
的動作而已,速度不會太慢。
09/07 04:43, 3F

09/07 04:44, , 4F
加上原本某些狀況 compiler 可以直接做 NRVO,
09/07 04:44, 4F

09/07 04:45, , 5F
所以原本我的 code 就常常是直接 by value 傳回。
09/07 04:45, 5F

09/07 05:56, , 6F
回文bot又出現了XD
09/07 05:56, 6F

09/07 08:30, , 7F
t 大說的沒錯, 直接回傳 vector<orbital>( ... ) 就好
09/07 08:30, 7F

09/07 08:32, , 8F
就可以用by value的方式傳出來
09/07 08:32, 8F
※ 編輯: loveme00835 來自: 140.121.197.115 (09/07 09:06)

09/07 09:34, , 9F
太感謝了 (∩_∩) 受益良多
09/07 09:34, 9F
文章代碼(AID): #1CXIS_XW (C_and_CPP)
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 2 之 2 篇):
文章代碼(AID): #1CXIS_XW (C_and_CPP)