[STL ] 是否可繼承STL類別?

看板C_and_CPP (C/C++)作者 (耗呆小綿羊)時間16年前 (2010/01/15 07:23), 編輯推噓4(4082)
留言86則, 11人參與, 最新討論串1/1
請教各位大大,直接繼承 STL 類別的作法是否適當? 如果這是不適當的作法,其缺點為何? 例如:class CVector: public vector<int> {...} vector<int> 沒有我需要的函式,我新建一個類別繼承它, 在這個新建類別增加我所需要的函式。 -- 耗呆小綿羊~ ~~~個人網頁:http://tw.myblog.yahoo.com/mjshya/ -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 59.121.2.131

01/15 08:49, , 1F
想知道+1
01/15 08:49, 1F

01/15 08:58, , 2F
想知道+1 ^^
01/15 08:58, 2F

01/15 10:30, , 3F
可以呀, 沒問題
01/15 10:30, 3F

01/15 12:08, , 4F
是可以 不過最好不要 container dtor不是virtual
01/15 12:08, 4F

01/15 12:09, , 5F
Effective C++ 2/e item 14有詳細解說
01/15 12:09, 5F

01/15 13:19, , 6F
3F 片倫 XD
01/15 13:19, 6F

01/15 14:35, , 7F
可以, 我覺得最好private 繼承, 類似composition
01/15 14:35, 7F

01/15 14:36, , 8F
來源同5樓
01/15 14:36, 8F

01/15 15:28, , 9F
@yoco315: 我哪裡騙人了? 明明就可以呀
01/15 15:28, 9F

01/15 15:29, , 10F
有沒有 virtual dtor 這些, 無論你在 inherit 任何 stl
01/15 15:29, 10F

01/15 15:29, , 11F
或非 stl 的 class 也要留意的, 和這問題沒有關係吧
01/15 15:29, 11F

01/15 15:30, , 12F
另 private 繼承也不合原問,因為他是想增加某method.
01/15 15:30, 12F

01/15 15:31, , 13F
用 private inheritence, 本身 vector 提供的東西就完
01/15 15:31, 13F

01/15 15:31, , 14F
全不 visible to outside 了
01/15 15:31, 14F

01/15 15:37, , 15F
答案是 private 繼承 + 重新 wrap 一次 base 的 methods。
01/15 15:37, 15F

01/15 15:39, , 16F
先用這種方法做出帶 virtual function 的可繼承基底,以後
01/15 15:39, 16F

01/15 15:40, , 17F
樓上所說的不是不可以, 但不太算是新增 method 了
01/15 15:40, 17F

01/15 15:40, , 18F
想再繼承就很方便,但 ctor 這類東西繼承了還是得重包一次
01/15 15:40, 18F

01/15 15:40, , 19F
因為新的 class 不再 is-a vector
01/15 15:40, 19F

01/15 15:41, , 20F
怎麼不算是新增 method?只是多做一點準備的工而已。
01/15 15:41, 20F

01/15 15:41, , 21F
本來就不能有 is-a 關係,is-a 必須實現多型語意,
01/15 15:41, 21F

01/15 15:42, , 22F
programmer 可以寫 vector<int> *v = new MyVector;
01/15 15:42, 22F

01/15 15:42, , 23F
然後 delete v;
01/15 15:42, 23F

01/15 15:43, , 24F
然後就.....是沒有 virtual dtor 可能發生的問題會發生。
01/15 15:43, 24F

01/15 15:43, , 25F
為什麼 "本來就不能有 is-a" ? public inheritence 就
01/15 15:43, 25F

01/15 15:44, , 26F
所以應該是使用 STL 容器的 class 實作一個可以延伸的基底
01/15 15:44, 26F

01/15 15:44, , 27F
類別,也就是 is-implement-in-terms-of,再繼承這種類別
01/15 15:44, 27F

01/15 15:44, , 28F
才可以有 is-a 關係。
01/15 15:44, 28F

01/15 15:44, , 29F
是了啦?
01/15 15:44, 29F

01/15 15:46, , 30F
public 繼承是 is-a 的必要條件,但不是充分條件。
01/15 15:46, 30F

01/15 15:47, , 31F
只是要留心有哪些東西沒 virtual, 但加 method 這類程
01/15 15:47, 31F

01/15 15:47, , 32F
在 Java 的話,因為預設 dynamic binding,所以才等價。
01/15 15:47, 32F

01/15 15:47, , 33F
度, 用 public inheritence 沒有什麼問題吧
01/15 15:47, 33F

01/15 15:48, , 34F
你說的這個 point, 與是不是 stl 沒直接關係.一向在C++
01/15 15:48, 34F

01/15 15:48, , 35F
要 inherit 別的 class, 都要留心 virtual 與否. 這會
01/15 15:48, 35F

01/15 15:49, , 36F
is-a 是一種 OO 概念,C++ 要充分支援它並不能單靠 public
01/15 15:49, 36F

01/15 15:49, , 37F
影響 method overriding 的結果, 但並不令 is-a 關係不
01/15 15:49, 37F

01/15 15:49, , 38F
繼承,這也是為什麼 N 年前 Effective C++ "2/e" 就已經
01/15 15:49, 38F

01/15 15:50, , 39F
列出了 Item35: Make sure public inheritance models
01/15 15:50, 39F

01/15 15:50, , 40F
存在. 只是 "雖然MyVector is-a vector, 但由於 vector
01/15 15:50, 40F

01/15 15:50, , 41F
"isa."
01/15 15:50, 41F

01/15 15:50, , 42F
的某某 method 非 virtual, 所以不適合 override" 而已
01/15 15:50, 42F

01/15 15:51, , 43F
我好想建議兩位回文章來討論...XDDD
01/15 15:51, 43F

01/15 15:51, , 44F
我也覺得好亂 :P
01/15 15:51, 44F

01/15 15:52, , 45F
問題不是出在適不適合 override,而是 dervied class 必須
01/15 15:52, 45F

01/15 15:52, , 46F
override base 的 dtor,但無法這麼做,使 is-a 語意不全
01/15 15:52, 46F

01/15 16:04, , 47F
要是自己本身根本沒有 extra dtor logic 的話, 根本不
01/15 16:04, 47F

01/15 16:05, , 48F
需要 override dtor 也沒問題呀, 這就和 override non-
01/15 16:05, 48F

01/15 16:05, , 49F
virtual method 的情況類似罷了
01/15 16:05, 49F

01/15 16:06, , 50F
is-a 語意並不會因為不能 override dtor 而不全...
01/15 16:06, 50F

01/15 16:07, , 51F
只是當有 custom dtor logic 的話, 就要知道因為 base
01/15 16:07, 51F

01/15 16:07, , 52F
class dtor 非 virtual, 這情況我不能直接 override 了
01/15 16:07, 52F

01/15 16:13, , 53F
delete v 的語意應該是,我要摧毀任何 is-a vector<int>
01/15 16:13, 53F

01/15 16:14, , 54F
的類別實體,但是實際上的語意卻是只摧毀了屬於
01/15 16:14, 54F

01/15 16:14, , 55F
vector<int> 所屬的那個部分,即使你沒在 MyVector 裡加入
01/15 16:14, 55F

01/15 16:15, , 56F
任何 data members 或 allocate 任何資源,語意上卻還是完
01/15 16:15, 56F

01/15 16:15, , 57F
全不一樣的,實際上大部分的書也會告訴你 C++ std 對這行
01/15 16:15, 57F

01/15 16:16, , 58F
為未有定義,因為 C++ compiler 可以把任何程式碼偷偷安插
01/15 16:16, 58F

01/15 16:16, , 59F
在 dervied class 的 dtor,沒呼叫到就不會跑到。
01/15 16:16, 59F

01/15 16:17, , 60F
在你的編譯環境 compiler 不會插任何東西,只能代表這個
01/15 16:17, 60F

01/15 16:17, , 61F
做法在你的編譯環境可行;但無論如何它實施的行為確實是
01/15 16:17, 61F

01/15 16:18, , 62F
只摧毀到 base 所屬的那一部份,derived 的 dtor (不管是
01/15 16:18, 62F

01/15 16:18, , 63F
你手寫的還是 compiler 幫你產生的) 都從未被呼叫到。
01/15 16:18, 63F

01/15 16:19, , 64F
換句話說,delete v 的行為並未做了 C++ 解構物件應該做的
01/15 16:19, 64F

01/15 16:19, , 65F
事情,因為它沒有真正把整個物件解構,而是一部分。
01/15 16:19, 65F

01/15 16:22, , 66F
因此從抽象面說,就是:programmer 期望摧毀整個物件,但
01/15 16:22, 66F

01/15 16:22, , 67F
實際上卻是只有摧毀物件的一部份,即使它的行為正確,也沒
01/15 16:22, 67F

01/15 16:22, , 68F
有對程式的執行環境造成任何損害。
01/15 16:22, 68F

01/15 16:24, , 69F
實作面來說,就是 compiler 產生在 dervied class 裡的
01/15 16:24, 69F

01/15 16:24, , 70F
dtor 本來應該在摧毀整個物件時被呼叫到,但它沒有被呼叫
01/15 16:24, 70F

01/15 16:30, , 71F
而所謂「compiler 可以在 dtor」裡插入任何東西是一件很重
01/15 16:30, 71F

01/15 16:31, , 72F
要的事情,因為比較先進的 compiler 可能允許 user 下參數
01/15 16:31, 72F

01/15 16:32, , 73F
後內插一些分析程式的 code,用來統計或分析程式的行為,
01/15 16:32, 73F

01/15 16:32, , 74F
如 profiling / power consumption / thread anlaysis /
01/15 16:32, 74F

01/15 16:33, , 75F
memory leak detection 等等,以最後那個為例,可能就會
01/15 16:33, 75F

01/15 16:33, , 76F
讓程式執行下去後回報有 memory leak XD
01/15 16:33, 76F

01/15 16:52, , 77F
的確我沒有考慮到 compiler 自動安插的 dtor logic :)
01/15 16:52, 77F

01/15 16:53, , 78F
如果考慮這個在內的話的確不適合直接 inherit 了.
01/15 16:53, 78F

01/15 16:53, , 79F
多謝指教 :D
01/15 16:53, 79F

01/15 17:03, , 80F
不過, 如果肯定不會 delete thru vector* , 這也不是問
01/15 17:03, 80F

01/15 17:03, , 81F
題吧. 最重要是知道這樣做的後果
01/15 17:03, 81F

01/15 17:29, , 82F
即使這個繼承方式可以被編譯成功、執行無誤…
01/15 17:29, 82F

01/15 17:36, , 83F
而它仍然不是一種適當的繼承方式,對吧?
01/15 17:36, 83F

01/15 17:59, , 84F
大家應該用回文的@@a
01/15 17:59, 84F

01/15 20:27, , 85F
感謝大大們的解答!
01/15 20:27, 85F

01/15 22:56, , 86F
精彩
01/15 22:56, 86F
文章代碼(AID): #1BJwTwkP (C_and_CPP)
文章代碼(AID): #1BJwTwkP (C_and_CPP)