作者Ebergies (火神)
看板C_and_CPP
標題Re: [問題] 新手關於 #include 的問題
時間Fri Apr 8 23:15:18 2011
※ 引述《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