看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《littleshan (我要加入劍道社!)》之銘言: : 沒那麼單純喔~ : 假設原本的 b.h 是這樣 : b.h: : class B { : private: : A my_a_obj; : public: : void do_something(); // do something with my_a_obj; : }; : 然後 foo.cpp 用到 b.h : #include <a.h> // because B uses A as its member : #include <b.h> : void foo(){ : B somb_b_obj; : some_b_obj.do_something(); : } : 目前看起來很 OK 可以用 : 過了一週 b.h 做了一些新功能,加入一個新的物件 C : class B { : private: : A my_a_obj; : C my_c_obj; : public: : void do_something(); // do something with my_a_obj : void do_something_else(); // do somethiing with my_c_obj : }; 回文賺點文章數 (咦) 以上面的例子來看,通常的寫法應該如同下面的狀況 : b.h: class A; : class B { : private: : // A my_a_obj; A *my_a_obj; : public: : void do_something(); // do something with my_a_obj; void maybe_do_more( A *a); : }; : 然後 foo.cpp 用到 b.h // We don't need a.h because my_a_obj is a pointer : // #include <a.h> // because B uses A as its member : #include <b.h> : void foo(){ : B somb_b_obj; : some_b_obj.do_something(); : } 這個時候有個 bar.cpp 也用到 b.h 如下 #include <a.h> // We use a because we want to allocate A #include <b.h> void bar() { B some_b; A some_a; b.maybe_do_more( &some_a); } 上面兩個例子,若更改 a.h 則只有 bar.cpp 需要重編, 這部分在專案越大省的時間越多 至於加入 c.h 怎麼辦? class C; : class B { : private: : // A my_a_obj; : // C my_c_obj; A *my_a_obj; C *my_c_obj; : public: : void do_something(); // do something with my_a_obj : void do_something_else(); // do somethiing with my_c_obj : }; 其實兩個檔都不用動的,因為 pointer 大小不隨 class 而變 因此 compiler 只需要知道它的名字就可以了 也就是你之前講的 forward declaration : 很不幸的,foo.cpp 雖然完全沒呼叫到新功能 : 也根本不知道 my_c_obj 的存在 : 但因為 B 物件的成員變了 : 所以你一定要在 foo.cpp 中去 include c.h : 不然編不過去 所以基本上除非是 value class 不然的話我們都會把標頭分開 : 那麼 foo.cpp 是不是又要把 #include <a.h> 這一行拿掉? : 即使他呼叫 do_something() 的方式完全都一樣 foo.cpp 的確不該為他不知道的東西付出代價 所以才有以上的方法 : 所以說 : 在 header 中引入 header 是必要的 : 照理來說 B class 若只有實作層次上的改變 : 那依賴它的 foo.cpp 應該也不需要修改 : 只需要重新編譯 同上,我認為是不必要的 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 175.180.111.210 ※ 編輯: Ebergies 來自: 175.180.111.210 (04/08 23:16)
loveme00835:必要的, 當你為了->付出執行效率與閱讀時間, 會恨自己 04/08 23:18
loveme00835:為什麼不要寫直接一點, 重編其實還沒有比可讀性重要 04/08 23:19
Ebergies:可讀性...? 04/08 23:20
loveme00835:把成員變成只包含指標的一個極致手法就是Pimpl idom 04/08 23:22
Ebergies:但這與可讀性有關嗎? 04/08 23:23
loveme00835:該手法在存取類別成員時, 至少要透過兩層取值 04/08 23:23
loveme00835:pimpl->a.function() 如果對象又是指標 04/08 23:24
loveme00835:pimpl->a->function(), 你再玩大一點 04/08 23:25
loveme00835:this->pimpl->a->function() 就會造成典型的重複程式 04/08 23:25
loveme00835:碼過多的情形, 也為了不必要的東西佔了過多版面 04/08 23:26
Ebergies:其實... 我看不出來為何要先弄一個 pimpl->a 04/08 23:26
loveme00835:上面有關鍵字阿 @_@ 04/08 23:29
legnaleurc:說複雜也只是多一個 header 要去看 private class 的 04/08 23:30
legnaleurc:定義吧, 至少如果我釋出的是 lib, 我會全部用 pimpl 04/08 23:30
Ebergies:我是沒去看... 不過我猜如果他需要弄一個 pimpl 04/08 23:30
Ebergies:那一定跟這裡的訴求沒有關係也跟我的實作無關 04/08 23:31
legnaleurc:但如果只有內部會使用到, 就沒必要用 pimpl 04/08 23:31
Ebergies:因為其實你只需要 a->function() 不就好了 04/08 23:31
loveme00835:恩, 我說的是開發端的實作 04/08 23:34
loveme00835:但從介面來看, 傳址不改值 and 傳參考卻會改值, 呼叫 04/08 23:36
loveme00835:叫端的閱讀也會不利 04/08 23:36
loveme00835:b.do_something( &a ); // 他會改到引數嗎? 04/08 23:41
loveme00835:b.do_something( a ); // 他會改到引數嗎? 04/08 23:42
loveme00835:習慣上來說, 傳址就是要改值(或是節省時間), 直接丟進 04/08 23:43
loveme00835:去就是傳值, 這時來一個 ref to non-const, 何必虐待 04/08 23:44
loveme00835:人呢? 04/08 23:44