Re: [問題] 新手關於 #include 的問題

看板C_and_CPP (C/C++)作者 (火神)時間15年前 (2011/04/08 23:15), 編輯推噓2(2024)
留言26則, 3人參與, 最新討論串4/10 (看更多)
※ 引述《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)

04/08 23:18, , 1F
必要的, 當你為了->付出執行效率與閱讀時間, 會恨自己
04/08 23:18, 1F

04/08 23:19, , 2F
為什麼不要寫直接一點, 重編其實還沒有比可讀性重要
04/08 23:19, 2F

04/08 23:20, , 3F
可讀性...?
04/08 23:20, 3F

04/08 23:22, , 4F
把成員變成只包含指標的一個極致手法就是Pimpl idom
04/08 23:22, 4F

04/08 23:23, , 5F
但這與可讀性有關嗎?
04/08 23:23, 5F

04/08 23:23, , 6F
該手法在存取類別成員時, 至少要透過兩層取值
04/08 23:23, 6F

04/08 23:24, , 7F
pimpl->a.function() 如果對象又是指標
04/08 23:24, 7F

04/08 23:25, , 8F
pimpl->a->function(), 你再玩大一點
04/08 23:25, 8F

04/08 23:25, , 9F
this->pimpl->a->function() 就會造成典型的重複程式
04/08 23:25, 9F

04/08 23:26, , 10F
碼過多的情形, 也為了不必要的東西佔了過多版面
04/08 23:26, 10F

04/08 23:26, , 11F
其實... 我看不出來為何要先弄一個 pimpl->a
04/08 23:26, 11F

04/08 23:29, , 12F
上面有關鍵字阿 @_@
04/08 23:29, 12F

04/08 23:30, , 13F
說複雜也只是多一個 header 要去看 private class 的
04/08 23:30, 13F

04/08 23:30, , 14F
定義吧, 至少如果我釋出的是 lib, 我會全部用 pimpl
04/08 23:30, 14F

04/08 23:30, , 15F
我是沒去看... 不過我猜如果他需要弄一個 pimpl
04/08 23:30, 15F

04/08 23:31, , 16F
那一定跟這裡的訴求沒有關係也跟我的實作無關
04/08 23:31, 16F

04/08 23:31, , 17F
但如果只有內部會使用到, 就沒必要用 pimpl
04/08 23:31, 17F

04/08 23:31, , 18F
因為其實你只需要 a->function() 不就好了
04/08 23:31, 18F

04/08 23:34, , 19F
恩, 我說的是開發端的實作
04/08 23:34, 19F

04/08 23:36, , 20F
但從介面來看, 傳址不改值 and 傳參考卻會改值, 呼叫
04/08 23:36, 20F

04/08 23:36, , 21F
叫端的閱讀也會不利
04/08 23:36, 21F

04/08 23:41, , 22F
b.do_something( &a ); // 他會改到引數嗎?
04/08 23:41, 22F

04/08 23:42, , 23F
b.do_something( a ); // 他會改到引數嗎?
04/08 23:42, 23F

04/08 23:43, , 24F
習慣上來說, 傳址就是要改值(或是節省時間), 直接丟進
04/08 23:43, 24F

04/08 23:44, , 25F
去就是傳值, 這時來一個 ref to non-const, 何必虐待
04/08 23:44, 25F

04/08 23:44, , 26F
人呢?
04/08 23:44, 26F
文章代碼(AID): #1DdoQ98j (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1DdoQ98j (C_and_CPP)