Re: [問題] 類別的傳遞
※ 引述《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
09/07 04:42, 1F
→
09/07 04:43, , 2F
09/07 04:43, 2F
→
09/07 04:43, , 3F
09/07 04:43, 3F
→
09/07 04:44, , 4F
09/07 04:44, 4F
→
09/07 04:45, , 5F
09/07 04:45, 5F
推
09/07 05:56, , 6F
09/07 05:56, 6F
→
09/07 08:30, , 7F
09/07 08:30, 7F
→
09/07 08:32, , 8F
09/07 08:32, 8F
※ 編輯: loveme00835 來自: 140.121.197.115 (09/07 09:06)
推
09/07 09:34, , 9F
09/07 09:34, 9F
討論串 (同標題文章)