討論區快速選單
知識庫快速選單
政府補助!學嵌入式+物聯網 軟體開發過程中有哪些資安漏洞? 網路投保旅行平安險
[ 回上頁 ] [ 討論區發言規則 ]
繼承破壞封裝
更改我的閱讀文章字型大小
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/16 下午 08:20:39
所謂封裝是指物件的屬性(成員變數值)不能被外界直接存取,而須經由其提供的方法(成員函數),為什麼要這麼做呢,這樣物件的屬性狀態有變動時,其相關的動作才能被執行,如以下的例子:

class Parent
{
  int _i;
public:
  F(int i)
  {
    _i = i + 20;
  }
};

但是有句話說「繼承破壞封裝」,我怎麼看不出要怎麼破壞,誰能做個子類別來破看看
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/17 上午 12:20:16
這裡有一個例子的解釋

http://www.cnblogs.com/nuaalfm/archive/2010/04/23/1718453.html

class
{
  var 羽毛;
public:
  void 飛()
  {
    使用有羽毛的翅膀飛了
  }
};

class 鴨子:public 鳥
{
};

鴨子不想飛,但因用"繼承"的方法,造成沒法封裝 飛(),所以叫做 繼承破壞封裝 = ="

這是正解還是冷笑話 :D
作者 : chiuinan2(青衫)討論區板主 Visual C++ .NET卓越專家VC++一代宗師Visual Basic優秀好手資訊類作業求救卓越專家一般曠世奇才程式設計甘苦談優秀好手C++ Builder優秀好手上班族的哈拉園地優秀好手C++頂尖高手Assembly優秀好手貼文超過3000則人氣指數超過150000點
[ 貼文 3732 | 人氣 170106 | 評價 34520 | 評價/貼文 9.25 | 送出評價 125 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/17 上午 02:46:46
我不知什麼叫"繼承破壞封裝", 請其他人回覆.

至於你的例子, 以及那篇文, 個人覺得誤解了父子繼承關係. 父物件的method, 應該是要有共同性, 下層子物件全部皆然. 不然弄一個"動物"物件, 說有"4隻腳", 然後因為"人"是"動物"的子物件, 所以有"4隻腳", 那就大誤特誤了. 這是物件設計上的問題, 不是物件技術本身的問題.
作者 : jonay(jonay) VC++優秀好手C++ Builder優秀好手C++優秀好手貼文超過500則
[ 貼文 887 | 人氣 8025 | 評價 5030 | 評價/貼文 5.67 | 送出評價 30 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/17 上午 06:18:19
是不是在說這個
http://www.cnblogs.com/whitewolf/archive/2010/05/03/1726519.html

講的是is a 和 have a的相對關係?
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/17 上午 09:57:46
to 青衫:
我知那例子的的不合理,本來在查資料搞得心情鬱悶,看到那例子差點讓我笑到噴血,鬱悶一掃而空,所以拿來共賞

to jonay:
繼承破壞封裝 最常在 繼承 vs 組合 的探討中看到,就我個人看法,繼承 和 組合最主要的差別是組合可以自由更換父類別(物件的屬性相相當於父類別),至於 繼承破壞封裝 的說法根本是鬼扯。

勉強還能接受的說法是採用 繼承 在某些情況下,把封裝的部份開放給子類別,因而有 繼承破壞封裝 的疑慮,但卻說這可用 組合 來避免。可是若可用 組合 來避免就不要開放給子類別不也一樣,若非得開放給子類別的情況,用 組合 一樣沒法解決,所以這說法也是矛頓

作者 : jonay(jonay) VC++優秀好手C++ Builder優秀好手C++優秀好手貼文超過500則
[ 貼文 887 | 人氣 8025 | 評價 5030 | 評價/貼文 5.67 | 送出評價 30 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/17 下午 03:53:56
have a
比如說一個人有一個心臟
而心可以拿出來裝到另一個人的身體中還可以正常使用(結構完整)
但是不會有人將心臟內的心房拿出來裝到腎內做pump

is a
我一直覺得父類別和子類別的說法不適當(但大家都這麼用)
它只有一個,得到的是血脈(我個人的說法是:子是父的再強化(細部)描述)
因此沒有"封裝"的問題(只有public或private血源的稀薄程度)
只是父類有的func若子類也有,就會產生遮閉效應(因為只有一個)
就好像沒法向左看的同時向右看(這不是影分身)

而"繼承破壞封裝"
好像在講改了父的func會影晌子的同一個func? (但是它只有一個,除非在子的func中呼叫父的同一func)
我總覺得這是該作者在說have a的好處和使用乾淨而故意打壓is a用的
但是這二者在觀念和使用上本來就目標不同


應該是這句話造成的:

繼承中父類定義了子類的部分實現,而子類中又會重寫這些實現,修改父類的實現,
設計模式中認爲這是一種破壞了父類的封裝性的表現。這個結構導致結果是父類實現的任何變化,
必然導致子類的改變。然而組合這不會出現這種現象




作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/17 下午 04:34:43
class Child:private Parent
{
};



class Child
{
private:
  Parent p;
};

意思是一樣的,但 組合 強調的是

class Child
{
private:
  Parent *p;
};

至於封裝的意思我在一開始有特別做標準說明,所以「繼承破壞封裝」就讓我陷於這範疇內思考,以至於看到 http://www.cnblogs.com/nuaalfm/archive/2010/04/23/1718453.html 那個鴨子的例子解釋一時讓我噴血,不過後來仔細想想,把視野放大一點,那例子說法好像也沒錯,若繼承造成想把隱藏的功能沒法隱藏(先別管實際是否正確,只做抽象層次思考),好像也是 繼承破壞封裝,只是感覺像在玩文字遊戲,像在狡辯。

若只限標準封裝的意思範疇內思考,「繼承破壞封裝」到底是什麼意思??
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/17 下午 04:49:42

>應該是這句話造成的:
>
>繼承中父類定義了子類的部分實現,而子類中又會重寫這些實現,修改父類的實現,
>設計模式中認爲這是一種破壞了父類的封裝性的表現。這個結構導致結果是父類實現的任何變化,
>必然導致子類的改變。然而組合這不會出現這種現象

我認為這說法是不恰當對比,應該是要在 組合 用法中,修改組合元件(相當於修改父類別)的實現,若能正確執行,把這組合元件拿來當父類別用是否就不行,這樣來做對比才正確
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 上午 09:47:34
>繼承中父類定義了子類的部分實現,而子類中又會重寫這些實現,修改父類的實現,
>設計模式中認爲這是一種破壞了父類的封裝性的表現。這個結構導致結果是父類實現的任何變化,
>必然導致子類的改變。然而組合這不會出現這種現象
繼承不會破壞封裝!
重寫函式只是重新訂義子類別成員,並沒有導致子類別的改變。
虛擬繼承有一點改變子類別的味道,但那是子類別定義時就希望由父類別來實現虛擬成員。
這也不應算是破壞封裝,所謂封裝是指把不想見光的成員包起來,並不是在於公開的方法是否改變。
要說C++的類別機制有什麼會破壞封裝,應該是friend吧!?
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 上午 09:49:40
訂正一下:
重寫函式只是重新訂義子類別成員在父類別上,並沒有導致子類別的改變。
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 上午 09:58:11
這就很像 有門不走愛爬窗
結果哪天不小心爬到一個太高的
摔了下來就在那罵OOXX...
繼承的規範就那幾點 不遵守那怎能怪規範??
如果大家都不照著紅綠燈走 那出車禍就是常有的
我覺得 設計模組 設計概念之類的
都是一種改善程式開發效率的概念與方法
如果說要說繼承破壞封裝性
那還不如說繼承者違反依賴倒轉規定...

另外我個人是認為 protected 屬性才有破壞的可能

class A
{
protected:
int mA[10];
};

class B : public A
{
public:
int *Get(){ return mA; }
};

以上由於B的錯誤繼承 破壞了A設計者原本希望的mA陣列的封裝


作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 上午 10:04:41
因為我剛PO文 旁邊的說沒破壞繼承的規定 所以特別講解一下
繼承不只有是程式碼上的繼承而已
依賴倒轉也不僅僅只是實現相同的方法而已
這是一種概念
所以 由類別A來看
開發者將mA設定為protected屬性
這僅僅代表 他預估 後續繼承類別 可能會需要對這陣列直接操作
但是他又不期望最終使用者會對mA進行操作
不然他就直接把mA設為public就好了不是?
所以上面的例子違反了~~精神繼承!!! XD
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 上午 11:58:26
另外我個人是認為 protected 屬性才有破壞的可能

>class A
>{
>protected:
>int mA[10];
>};
>class B : public A
>{
>public:
>int *Get(){ return mA; }
>};
>以上由於B的錯誤繼承 破壞了A設計者原本希望的mA陣列的封裝
mA 宣告為protected即表示不對子類別封裝保密。
既沒有對子類別封裝保密,子類別何來破壞封裝?
如果這不是設計者原意,那麼就是設計者寫錯了!
舉個例子:
class A
{
public:
int mA;
};
main()
{
A Aobj;
aObj.mA=0;//說public破壞了mA的封裝是對的嗎?
}
mA 宣告為public即表示不對外部程式封裝保密。
既沒有對外部程式封裝保密,外部程式何來破壞封裝?
OOP是在建立一套規則。
程式員遵循這套規則可以獲得OOP設計的好處。
並不是程員想的1程式寫成2,OOP還可以使程式變成1的結果。
能這樣心想就事成,就連程式都不用寫了,用想的就好了。
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 12:04:49
所以大家對 「繼承破壞封裝」 心裡(不代表事實)的看法也是認為是鬼扯嗎

可是「繼承破壞封裝」傳頌那麼廣,應不會是空穴來風吧,會不會是某人翻譯上的誤解,要是能有一個和它搭配的例子就容易理解了
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 02:58:06

>另外我個人是認為 protected 屬性才有破壞的可能
>
>>class A
>>{
>>protected:
>>int mA[10];
>>};
>>class B : public A
>>{
>>public:
>>int *Get(){ return mA; }
>>};
>>以上由於B的錯誤繼承 破壞了A設計者原本希望的mA陣列的封裝
>mA 宣告為protected即表示不對子類別封裝保密。
>既沒有對子類別封裝保密,子類別何來破壞封裝?
>如果這不是設計者原意,那麼就是設計者寫錯了!

protected 有可能符合問題的情況,protected 表示對子類別開放,但對外界仍是保密的,有可能子類別破壞了對外界的封裝

但卻說 組合 能避免這情況的發生,即表示 protected 是不須要的,那表示是 class A 設計錯誤,不能怪罪到 class B

若 protected 是須要的,那麼用 組合 也一樣沒法解決

作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 03:56:02

>
>>另外我個人是認為 protected 屬性才有破壞的可能
>>
>>>class A
>>>{
>>>protected:
>>>int mA[10];
>>>};
>>>class B : public A
>>>{
>>>public:
>>>int *Get(){ return mA; }
>>>};
>>>以上由於B的錯誤繼承 破壞了A設計者原本希望的mA陣列的封裝
>>mA 宣告為protected即表示不對子類別封裝保密。
>>既沒有對子類別封裝保密,子類別何來破壞封裝?
>>如果這不是設計者原意,那麼就是設計者寫錯了!
>
>protected 有可能符合問題的情況,protected 表示對子類別開放,但對外界仍是保密的,有可能子類別破壞了對外界的封裝
>
>但卻說 組合 能避免這情況的發生,即表示 protected 是不須要的,那表示是 class A 設計錯誤,不能怪罪到 class B
>
>若 protected 是須要的,那麼用 組合 也一樣沒法解決

我想到了,"若 protected 是須要的,那麼用 組合 也一樣沒法解決" 我是把它理解為 "就沒辦法用組合" 了,因 class A 須被繼承,但 class A 可以由 class C 繼承再給 class B 組合,這樣就算 class C 會洩漏機密,但 class B 只用到 class A 這層介面,所以仍能對外保密,這樣說算不算完美,同意的話請給個掌聲 ^^
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 04:13:29
>protected 有可能符合問題的情況,protected 表示對子類別開放,
>但對外界仍是保密的,有可能子類別破壞了對外界的封裝
如果像這樣也算是子類別破壞父類別的封裝:
>>class A
>>{
>>protected:
>>int mA[10];
>>};
>>class B : public A
>>{
>>public:
>>int *Get(){ return mA; }
>>};
那麼父類別也可以自己破壞封裝:
class A
{
protected:
int mA[10];
public:
int *Get(){ return mA; }
};
本來方法就可以依權限存取資料成員,怎麼變成破壞?
如果這樣算是破壞封裝的話,那麼這樣的破壞也還是和繼承無關。
我認為Get不論寫在父或子類別上,都是透過方法間接存取,都不算是破壞封裝。
如果mA資料成員,不該被Get,但麼就不該寫Get(不論父或子類別)方法。
寫了不該寫的Get方法,算是程式員寫錯,不是繼承有問題。
OOP是要程式員遵循規則,不是用來防止合乎規則但亂寫的程式。

作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 04:22:43

>int *Get(){ return mA; }

這個函數算是破壞封裝吧,讓外界可得到被保護的資料,對其做存取

不然什麼叫破壞封裝
作者 : jonay(jonay) VC++優秀好手C++ Builder優秀好手C++優秀好手貼文超過500則
[ 貼文 887 | 人氣 8025 | 評價 5030 | 評價/貼文 5.67 | 送出評價 30 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 04:24:01
人類的許多科技是從自然界找靈感的
我一直不喜歡用三角形、方形、圓形這些來解說OOP的理論
這是數學家想出來的,一般人怎麼聽的懂?(想想曾經或還在這堶掛襤囿漱H就知道)

直接用生物、生命來解說不是比較有血有肉
比如public、private類
就好像人穿一件衣服上有口袋
在外面的口袋每個人都可以伸手進去拿東西

而內部的暗袋必需要透過原主人的"手",才能將東西取出
這樣不是符合自然、天道(至於其它奇奇怪怪的設計就忘了吧,focus在這上面只會害了自已)

比如protect
我就覺得這是個介於public和private中間的畸形兒





作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 04:37:55
>我想到了,"若 protected 是須要的,那麼用 組合 也一樣沒法解決"
> 我是把它理解為 "就沒辦法用組合" 了,因 class A 須被繼承,
>但 class A 可以由 class C 繼承再給 class B 組合,
>這樣就算 class C 會洩漏機密,但 class B 只用到 class A 這層介面,
>所以仍能對外保密,這樣說算不算完美,同意的話請給個掌聲 ^^
有點給它複雜化了...
什麼是破壞?違反原本設計,才算是破壞,是吧?
protected:
 int mA;
mA 宣告為protected是什麼意思?
不就是開放給子類別直接存取嗎?
那麼子類別要怎麼搞mA都不能說破壞,是不是?
在街上擺一桌酒席,規定凡中華民國籍均可以吃。
那麼人家都拿身份證來吃了,怎麼能說人家長得不夠漂亮,破壞規矩?
如果設計原意是只給子類別間接存取,那麼應該這樣寫:
class A{
private:
 int mA;
protected:
GetBySubclass(){return mA;}
PutBySubClass(int iUpdate){mA=iUpdate;}
};
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 04:55:07
>>int *Get(){ return mA; }
>這個函數算是破壞封裝吧,讓外界可得到被保護的資料,對其做存取
>不然什麼叫破壞封裝
這應該是你我意見最大的差異了吧^^
方法本來就可能存取private/protected的成員,這不能算是破壞封裝。
要不然OOP會玩不下去...
當然,寫出這樣的程式:
class A{
private:
int mA;
pubic:
Get(){return mA;}
Put(iny iNew){mA=iNew;}
};
你可以說 Get/Put使得mA的封裝變得沒有意義,但不能說Get/Put"破壞"什麼。
通常封裝的資料成員,要提供存取的方法都會加上什麼,例如:
class A{
private:
int iReadCount;
int mA;
pubic:
Get(){
iReadCount++;
return mA;
}
Put(iny iNew){
iReadCount=0;
mA=iNew>10?10:iNew;
}
};
這裡的Get/Put仍然有你認為的"破壞",但它是正常的OOP程式。
下面的類別,使得mA的封裝有意義,上面那個則否。
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 05:15:42
>人類的許多科技是從自然界找靈感的
>:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
>比如protect
>我就覺得這是個介於public和private中間的畸形兒
protected 就是雖是外面的口袋,但加了鎖。
有鑰匙的人都可以拿到上鎖袋裡的東西。
除了本人有鑰匙外,通過繼承也可以拿到鑰匙。
這樣說起來,protected 也是很自然是不是^^
要有血有肉,這裡有一篇血肉模糊的比喻:^^
http://ehome.hifly.to/showthread.php?postid=101#post101
作者 : jonay(jonay) VC++優秀好手C++ Builder優秀好手C++優秀好手貼文超過500則
[ 貼文 887 | 人氣 8025 | 評價 5030 | 評價/貼文 5.67 | 送出評價 30 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 06:02:53
如果我沒記錯
protect的解釋是

類可見(用)
物不可見(用)

有趣興的可以看這篇
http://blog.codingnow.com/2010/03/cpp_protected.html

至於文中的爸爸,我總覺得它應該是個物
friend就不說了,它就是為封裝動作開了後門

至於protect的設計
我的直覺是
一、符合數學家的三一率(這有點病態)
二、減少function的呼叫











作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 06:31:16
不好意思,或許大家對"封裝"的理解有所同,但我還是想
把我理解的封裝觀念,講清楚一點:
封裝有兩層意思:
1.打包:所有的成員打包成一個類別,不論是private,protected或public都是被打包的對像。
2.保護:限制某些成員(包括資料和方法)被直接存取。
保護的定義不是在使某些封裝成員和外界無關(和外界完全無關的成員是沒意義的)。
而是限制外界的直接存取!
像這樣的類別:
class A
{
private:
int mA;
public:
int *Get(){ return mA; }
};
外界只能透夠介面(方法)Get間接存取mA,所以mA的保護性質還是在的。
外界透過介面操作(存取也是一種操作)受保護的對象,本來就是OO的特質之一。
保護只是對"直接存取"而言,不是指介面(方法)。
如果類別介面寫得使保護對象,有保護跟沒保護一樣,那是程式員的問題,不是OOP的問題。
class A 提供了Get作讀取介面,還是有點意義:
使用外不能對mA作更改,只能讀取。
但若增加了寫入的方法呢:
class B
{
private:
int mA;
public:
int *Get(){ return mA; }
void Put(int iNew){ mA=iNew; }
};
看起來,class B使得mA的保護性蕩然無存!
但,要有錯只能說是程式員弄不清mA的保護性是什麼而使得
程式的一致性有問題。
即使是這樣,我還是看過有人程式是這樣寫,他們的理由是:
將來因應需要,想要在存取mA時可以加點料,只要在
Get/Put的介面修改一下就好了。這對程式的維護性,還是有意義。
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 06:48:19
>http://blog.codingnow.com/2010/03/cpp_protected.html
>>至於文中的爸爸,我總覺得它應該是個物
若它是可以套用在很多父子,人際關係上,它就是類別。

>>friend就不說了,它就是為封裝動作開了後門
同意!
前面我也說了,若要說什麼會破壞封裝性,就是:"friend"。
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 07:40:50
>有趣興的可以看這篇
>http://blog.codingnow.com/2010/03/cpp_protected.html
文中的這個類別成員存取權限,有點意思:
class foo {
protected: int a;
};
class foobar : public foo {
public:
int bar(foo * f) {
return this->a + f->a;//這裡f->a的存取違規
}
 };
我直覺是bar *f這裡寫錯了資料型態,應該是要寫成這樣才對:
int bar(foobar * f) {
return this->a + f->a;//這裡f->a的存取違規
}
若是作者原意是希望f不論是foo或foobar指標都可接受,應也不必寫到自覺不是味道:
class foo {
protected: int a;
static int get_a(foo *self) { return self->a;}
};
class foobar : public foo {
public: int bar(foo * f) { return this->a + get_a(f); }
};

我覺得像這樣寫,味道比較像原意要的:
class foo {
protected: int a;
public: int bar(foo * f) {return this->a + f->a;}
};
class foobar : public foo {
public: int bar(foobar * f) {return bar(f);}
 }

另外一種簡便但稍具危險性的作法(小孩勿玩);
class foo {
protected: int a;
};
class foobar : public foo {
public: int bar(foo * f) {return this->a + static_cast<foobar *>(f)->a;}
 }
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 07:42:14
訂正
我直覺是bar *f這裡寫錯了資料型態,應該是要寫成這樣才對:
int bar(foobar * f) {
return this->a + f->a;//這裡f->a的存取沒有問題
}
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 07:58:59
原諒我,再訂正一下(看來人老了,是不能閉著眼睛寫程式的):
我覺得像這樣寫,味道比較像原意要的:
class foo {
protected: int a;
public: int bar(foo * f) {return this->a + f->a;}
};
class foobar : public foo {
//public: int bar(foobar * f) {return bar(f);}//<--這裡根本是多餘的,多寫多錯!
 }

作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/18 下午 11:43:46

以下用程式表達我對 繼承破壞封裝 的看法,以及 組合 為什麼可以避免 繼承破壞封裝 的意義,純屬個人見解,不代表正解,很希望有人能提供最原始的見解來源

class A
{
protected:
  int i[2]; // 假設有某個理由須對子類別開放,但對外仍保護
public:
  A(int i1, int i2)
  {
    i[0] = i1;
    i[1] = i2;
  }

  virtual int Compute() = 0;
};

class B1:public A
{
public:
  B1(int i1, int i2)
    :A(i1,i2)
  {
  }
  virtual int Compute()
  {
    return i[0]+i[1];
  }

  int *Get() // class B1 很白目,繼承破壞封裝
  {
    return i;
  }
};

class B2
{
protected:
  A *p; // 採用 組合 模式挽救 claaa A 會被破壞封裝的疑慮
public:
  B2(int i1, int i2)
  {
    p = new B1(i1,i2);
  }
  virtual ~B2()
  {
    delete p;
  }
  virtual int Compute()
  {
    return p->Compute();
  }
};
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 上午 09:28:14

>另外我個人是認為 protected 屬性才有破壞的可能
>
>>class A
>>{
>>protected:
>>int mA[10];
>>};
>>class B : public A
>>{
>>public:
>>int *Get(){ return mA; }
>>};
>>以上由於B的錯誤繼承 破壞了A設計者原本希望的mA陣列的封裝
>mA 宣告為protected即表示不對子類別封裝保密。
>既沒有對子類別封裝保密,子類別何來破壞封裝?
>如果這不是設計者原意,那麼就是設計者寫錯了!
>舉個例子:
>class A
>{
>public:
>int mA;
>};
>main()
>{
>A Aobj;
>aObj.mA=0;//說public破壞了mA的封裝是對的嗎?
>}
>mA 宣告為public即表示不對外部程式封裝保密。
>既沒有對外部程式封裝保密,外部程式何來破壞封裝?
>OOP是在建立一套規則。
>程式員遵循這套規則可以獲得OOP設計的好處。
>並不是程員想的1程式寫成2,OOP還可以使程式變成1的結果。
>能這樣心想就事成,就連程式都不用寫了,用想的就好了。

我後面有強調 如果A開發者他將mA設為protected不設為public
代表他只對子類別開放 而不對外不開放
但是B的Get傳回了mA的指針
所以如果
int *pA = B.Get();
pA[1] = 100;
不就破壞了A開發者對mA的封裝??
因為只有持有pA指標者 就可以任意變更mA的資料
並且他無法得知A或B的生存週期
也無法得知對mA的變更是否引響到正常功能
我們這估且不論A開發者的設計錯誤
但是 B開發者既然要繼承A 那就要遵守A開發者的規範
如果你質疑他 那你可以不要繼承他
但是 繼承他的話 請不管在方法上或精神上一同繼承才對
我指出這問題只是想說出來這是一個漏洞
但不是用來質疑OO的不好
就像我強調的 學習OO學的是他的精神 而不是寫法
也不是要人像這樣在雞蛋裡挑骨頭一樣
(不是指大家的意見 而是指我用protected這樣來破壞封裝)

XD 目前在做大夜班作業員 沒想到一下班回來 就看到回覆數量飆漲 lol
希望能利用這兩天假日跟大家好好交流一下 XD

作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 上午 09:34:51
以上由於B的錯誤繼承 破壞了A設計者原本希望的mA陣列的封裝
mA 宣告為protected即表示不對子類別封裝保密。
既沒有對子類別封裝保密,子類別何來破壞封裝?
如果這不是設計者原意,那麼就是設計者寫錯了!

>protected 有可能符合問題的情況,protected 表示對子類別開放,但對外界仍是保密的,有可能子類別破壞了對外界的封裝
我認為問題不再用不用protected或者用不用組合
而是但卻說 組合 能避免這情況的發生,即表示 protected 是不須要的,那表示是 class A 設計錯誤,不能怪罪到 class B

實際上 繼承者的義務是?? 當你知道A開發者只想讓mA對繼承者開放
那繼承者卻把他對外開放不就是違背了A的設定嗎?
如果你覺得他設計不好 那你應該不要繼承他
而不是繼承之後再來怪罪他不好 畢竟他是已經定案或已經完成的
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 上午 09:36:56

我想到了,'若 protected 是須要的,那麼用 組合 也一樣沒法解決' 我是把它理解為 '就沒辦法用組合' 了,因 class A 須被繼承,但 class A 可以由 class C 繼承再給 class B 組合,這樣就算 class C 會洩漏機密,但 class B 只用到 class A 這層介面,所以仍能對外保密,這樣說算不算完美,同意的話請給個掌聲 ^^

不完美喔 = =
如同我上面說的一樣 B遵守A的規範
不管精神上或方法上
不就沒啥繼承破壞封裝性了不是??
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 上午 09:39:50
>本來方法就可以依權限存取資料成員,怎麼變成破壞?
>如果這樣算是破壞封裝的話,那麼這樣的破壞也還是和繼承無關。
>我認為Get不論寫在父或子類別上,都是透過方法間接存取,都不算是破壞封裝。
>如果mA資料成員,不該被Get,但麼就不該寫Get(不論父或子類別)方法。
>寫了不該寫的Get方法,算是程式員寫錯,不是繼承有問題。
>OOP是要程式員遵循規則,不是用來防止合乎規則但亂寫的程式。

B開發者錯再把指針傳了出去 所以破壞mA的封裝
因為在C++中 有指針 就....
另外 大大後面說的那句 才是我特別想強調的
B程序員根本不該做出Get這個方法才對 因為他違背了A開發者的規劃...
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 上午 09:46:16
>protected:
> int mA;
>mA 宣告為protected是什麼意思?
>不就是開放給子類別直接存取嗎?
>那麼子類別要怎麼搞mA都不能說破壞,是不是?
>在街上擺一桌酒席,規定凡中華民國籍均可以吃。
>那麼人家都拿身份證來吃了,怎麼能說人家長得不夠漂亮,破壞規矩?
>如果設計原意是只給子類別間接存取,那麼應該這樣寫:
>class A{
>private:
> int mA;
>protected:
>GetBySubclass(){return mA;}
>PutBySubClass(int iUpdate){mA=iUpdate;}
>};

在我上面PO文的mA他是一個陣列
有些人考量到繼承類別會變更操作陣列的方法
為了減少 函式的進出入操作
所以他對繼承者開放了mA陣列
但是B開發者為了讓自己方便存取mA陣列內資料
所以就做了一個 Get方法將原本應該保護的mA指針取出
然後就在自己另外一個依賴或聚合B的物件C內保存了mA指針到pA
B開發者心底想了 看這樣多輕鬆阿
我後面只要pA[X] = R; int Z = pA[5];
就可以再C內隨意的變更操作B提供的mA陣列
那請問一下 這樣有破壞B的封裝性了嗎??
那這樣一來 B程式員該不該打屁股阿 lol~~
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 上午 09:49:16

>>>int *Get(){ return mA; }
>>這個函數算是破壞封裝吧,讓外界可得到被保護的資料,對其做存取
>>不然什麼叫破壞封裝
>這應該是你我意見最大的差異了吧^^
>方法本來就可能存取private/protected的成員,這不能算是破壞封裝。
>要不然OOP會玩不下去...
>當然,寫出這樣的程式:
>class A{
>private:
>int mA;
>pubic:
>Get(){return mA;}
>Put(iny iNew){mA=iNew;}
>};
>你可以說 Get/Put使得mA的封裝變得沒有意義,但不能說Get/Put'破壞'什麼。
>通常封裝的資料成員,要提供存取的方法都會加上什麼,例如:
實際上 繼承者的義務是?? 當你知道A開發者只想讓mA對繼承者開放
那繼承者卻把他對外開放不就是違背了A的設定嗎?
如果你覺得他設計不好 那你應該不要繼承他
而不是繼承之後再來怪罪他不好 畢竟他是已經定案或已經完成的
>Put(iny iNew){
>iReadCount=0;
>mA=iNew>10?10:iNew;
>}
>};
>這裡的Get/Put仍然有你認為的'破壞',但它是正常的OOP程式。
>下面的類別,使得mA的封裝有意義,上面那個則否。
>

大大提的例子完全沒破壞性問題阿
因為傳出物件屬性的值並沒有破壞物件內部的可能性
因為持有那個值不能變更物件內部
但如果是
class A{
private:
int mA;
pubic:
int *Get(){return &mA;}
};
那這個Get才有破壞的問題喔
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 上午 09:52:49

>不好意思,或許大家對'封裝'的理解有所同,但我還是想
>把我理解的封裝觀念,講清楚一點:
>封裝有兩層意思:
>1.打包:所有的成員打包成一個類別,不論是private,protected或public都是被打包的對像。
>2.保護:限制某些成員(包括資料和方法)被直接存取。
>保護的定義不是在使某些封裝成員和外界無關(和外界完全無關的成員是沒意義的)。
>而是限制外界的直接存取!
>像這樣的類別:
>class A
>{
>private:
>int mA;
>public:
>int *Get(){ return mA; }
>};
>外界只能透夠介面(方法)Get間接存取mA,所以mA的保護性質還是在的。
>外界透過介面操作(存取也是一種操作)受保護的對象,本來就是OO的特質之一。
>保護只是對"直接存取"而言,不是指介面(方法)。
>如果類別介面寫得使保護對象,有保護跟沒保護一樣,那是程式員的問題,不是OOP的問題。
>像 class A 提供了Get作讀取介面,還是有點意義:
>使用外不能對mA作更改,只能讀取。
>但若增加了寫入的方法呢:
>class B
>{
>private:
>int mA;
>public:
>int *Get(){ return mA; }
>void Put(int iNew){ mA=iNew; }
>};
>看起來,class B使得mA的保護性蕩然無存!
>但,要有錯只能說是程式員弄不清mA的保護性是什麼而使得
>程式的一致性有問題。
>即使是這樣,我還是看過有人程式是這樣寫,他們的理由是:
>將來因應需要,想要在存取mA時可以加點料,只要在
>Get/Put的介面修改一下就好了。這對程式的維護性,還是有意義。
>

大大講的我大部分認同
但是

將來因應需要,想要在存取mA時可以加點料,只要在
Get/Put的介面修改一下就好了。這對程式的維護性,還是有意義。

那不能將mA拆出來嗎??
封裝封裝 不就是把固定的保留 把不定的移出麻...
因為你不能確保 那到那個指針的 都肯定會在物件消滅時清空該指針
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 上午 11:34:27

>
>我想到了,'若 protected 是須要的,那麼用 組合 也一樣沒法解決' 我是把它理解為 '就沒辦法用組合' 了,因 class A 須被繼承,但 class A 可以由 class C 繼承再給 class B 組合,這樣就算 class C 會洩漏機密,但 class B 只用到 class A 這層介面,所以仍能對外保密,這樣說算不算完美,同意的話請給個掌聲 ^^
>
>不完美喔 = =
>如同我上面說的一樣 B遵守A的規範
>不管精神上或方法上
>不就沒啥繼承破壞封裝性了不是??
>

從 A 立場來看, B 可以由任何人開發,若 B 採用繼承 A 的方式,不能事先假設 B 會遵守規範,只有 B 採用組合 A 的方式才有保障
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 12:06:42
從 A 立場來看, B 可以由任何人開發,若 B 採用繼承 A 的方式,
不能事先假設 B 會遵守規範,只有 B 採用組合 A 的方式才有保障

錯了 是A永遠都會假設B要遵守他的規範
因為B可以知道A但A不會知道B
A預期要被繼承 所以他會對繼承者提出要求
就跟我一開始說的一樣
如果 A想開放mA 就直接public了
再來說組合A?
如果是B去組合A那 請問mA是否要public?
如果不公開 那A要提供一堆操作mA的接口嚕?
但是A將mA設為protected目的是為了讓繼承者能對mA在處理
但是不想讓最終使用者去操作他
所以B組合A是與期望不合的
再來C繼承A 再給B組合?
這有點拖褲子放屁的感覺.....lol~~
假設A使用protected來設定mA是為了給繼承者對mA陣列的直接操作
那C繼承了A並對mA的操作實現了
那B組合C作啥?? 你規劃的B實際上已經算是最後使用者了
那如果C也搞了個 int *Get(){ return mA; } 勒??
再來如果C繼承了A但將對mA的操作想保留給B
那使用A指針的B應該是對操作mA無能為力吧??
因為A不會有int *Get(){ return mA; }.....
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 12:08:45
Re:LionX
>這裡的Get/Put仍然有你認為的'破壞',但它是正常的OOP程式。
>大大提的例子完全沒破壞性問題阿
>因為傳出物件屬性的值並沒有破壞物件內部的可能性
Put 會改變mA。
Get+Put相當於外部有了mA完全的存取權(間接)。
我也不同意這裡的Get/Put有破壞性的問題。
只是討論有了Get/Put,那mA的保護是否還有意義。

貼了那麼多篇回文,感到很抱歉的是,我沒注意到大部的討論是集中
在指標的問題。底下我再針對指標討論。
討論到指標前,我還是要再提"授權"的議提。
類別的privte/protected/public就是一種直接存取成員授權的機制。
1.private 授權類別本身存取;protected授權本身和子類別存取;public則授權任何程式存取。
2.C++的授權是完全授權,不是部份授權(充份授權表示可以對授權的成員隨意處置,包括再授權)。
以上兩點,若可以同意就往下看。
class A{protected: int mA;};
class B{public: int *Get(){return &mA;}};
這個class A授權子類別(B)可以隨意處置mA,不是嗎?那麼class B通過Get使得外部有了直接存取mA
的權利。B和外部都沒有違反規則:外部是經由B的授權,B則是經由A的授權。
這樣的結果,程式有沒有問題是另一件事,但至少"破壞"罪名應可免。
用一個有血有肉的例子:
爸爸很吝嗇,用錢的一個原則是絶不給外人花用;
一天,爸爸給兒子一萬元,結果兒子隔天就把一萬元送給了隔壁可鄰的阿婆。
請問有沒有破壞爸爸的用錢規則?
我覺得沒有,因為爸爸給兒子錢時並沒有附加限制兒子不能把錢用在什麼地方(完全授權)。
阿婆得到這筆錢花用,是經由兒子授權,不是向爸爸偷的。
如果爸爸給兒子這筆錢,但希望兒子用錢也要遵循爸爸的原則,那麼就不能充份授權。
而是經由用錢程序(方法)控制兒子用錢來達到了部份授權的目的。

OK,若我同意 class B 的Get是一種破壞(封裝)好了,那也和繼承無關啊(這是我前面貼文提過的)
例如class A改成這樣:
class A{
private: int mA;
public: int *Get(){return &mA}
};

不必經由繼承,class 本身就可以搞同樣的"破壞"不是嗎?
要搞破壞,既然大家都可以搞,那麼「繼承破壞封裝」,所言何來?
"繼承"為什麼要替大家擔下這個罪名?

(去吃中餐了,待會再續指標。感謝賞文,不論贊成否^^)
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 12:30:05
>貼了那麼多篇回文,感到很抱歉的是,我沒注意到大部的討論是集中
>在指標的問題。底下我再針對指標討論。
>討論到指標前,我還是要再提'授權'的議提。
>類別的privte/protected/public就是一種直接存取成員授權的機制。
>1.private 授權類別本身存取;protected授權本身和子類別存取;public則授權任何程式存取。
>2.C++的授權是完全授權,不是部份授權(充份授權表示可以對授權的成員隨意處置,包括再授權)。
>以上兩點,若可以同意就往下看。
>class A{protected: int mA;};
>class B{public: int *Get(){return &mA;}};
>這個class A授權子類別(B)可以隨意處置mA,不是嗎?那麼class B通過Get使得外部有了直接存取mA
>的權利。B和外部都沒有違反規則:外部是經由B的授權,B則是經由A的授權。
>這樣的結果,程式有沒有問題是另一件事,但至少'破壞'罪名應可免。
>用一個有血有肉的例子:
>爸爸很吝嗇,用錢的一個原則是絶不給外人花用;
>一天,爸爸給兒子一萬元,結果兒子隔天就把一萬元送給了隔壁可鄰的阿婆。
>請問有沒有破壞爸爸的用錢規則?
>我覺得沒有,因為爸爸給兒子錢時並沒有附加限制兒子不能把錢用在什麼地方(完全授權)。
>阿婆得到這筆錢花用,是經由兒子授權,不是向爸爸偷的。
>如果爸爸給兒子這筆錢,但希望兒子用錢也要遵循爸爸的原則,那麼就不能充份授權。
>而是經由用錢程序(方法)控制兒子用錢來達到了部份授權的目的。

這點我有點不認同 所以我才說這是一種精神上的不繼承
因為 C++不允許部分授權
所以 當A開發者將mA設為protected的話
B開發者應該了解 A作者僅僅只想要授權只到繼承者來操作而已
不然他public不就好了??
當然我是通常不這樣做 如果作也會在A內特別說明繼承規範
再來 繼承者要去繼承一個既成的類別時
不去破壞既成類別的設計規劃是最基本的原則
如果你覺得設計錯誤 可以不去繼承 可以另外寫一個
但是 如果你決定要繼承 就不能去違反繼承物件的規劃
就拿最近很流行的撿錢事件
撿到錢不要報酬跟要報酬都不違法吧??
那為啥要報酬的被罵的很慘??
因為他不符合道德規範對吧?
那道德規範為何勒? 就是大家默認應該遵守的對吧??
B直接使用int *Get(){ return mA; } 當然他不違反C++
但是 他違反了A開發者希望大家默認遵守的
當然如果有人不認為A開發者protected來設定mA是不想讓他對外開放
我也只能摸摸鼻子 不然勒....



>OK,若我同意 class B 的Get是一種破壞(封裝)好了,那也和繼承無關啊(這是我前面貼文提過的)
>例如class A改成這樣:
>class A{
>private: int mA;
>public: int *Get(){return &mA}
>};
>
>不必經由繼承,class 本身就可以搞同樣的'破壞'不是嗎?
>要搞破壞,既然大家都可以搞,那麼「繼承破壞封裝」,所言何來?
>'繼承'為什麼要替大家擔下這個罪名?
>
>(去吃中餐了,待會再續指標。感謝賞文,不論贊成否^^)

這樣來說 就是A自己破壞自己的封裝了阿..
想我學OO時第一堂課就是被罵這個 ㄖㄖa...
我沒有一值強調繼承破壞封裝
我想表達的是 繼承破壞封裝 也只是開發者自己搞的
遵守繼承對象的規範 就不會有破壞問題
對於你說繼承破壞封裝所言何來
其實就是一些OOXX作者 特別想強調
當某些XXOO的開發者 就可能繼承來亂搞你規劃的類別如此而已

再講一個

class A
{
private:
int mA;
};

class B : public A
{
public:
void Set(){ *this = 19; }
}

這個破壞如何??
備註:B是我隨便打的不確定能編譯過
我想表達的是由於C++有指針
所以繼承你可以亂搞來破壞
當然也可以遵守規則 是吧~~~??
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 12:57:05
另外為了避免大家把焦點擺放在 怎樣去破壞c++物件上
我這在說明一下 繼承破壞封裝
只是提出一個概念 指出在繼承使用上
如果遇到OOXX的開發者就可能破壞封裝的完整性
而並不是指 只有繼承才會破壞封裝完整性
例如:
class A
{
private:
int mA;
};

A gA;

void main()
{
*((int*)&gA) = 999;
}

你愛這樣來搞破壞 也沒人能阻止你對吧
畢竟你沒有違反編譯器的規範的話
他就是能編譯通過
但是 A開發者看到會不會想打你 這就兩說了...
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 01:05:05
夜深了(白天=大夜班的晚上) 總結一下 繼承破壞封裝

繼承破壞封裝 意指 當類別被繼承時

繼承者可能不依照原始類別的規劃來設定繼承類別

進而破壞原始開發者對整個架構的原始規劃

具體範例參考上面...大夜班ㄍ一ㄥ到現在很累了 ...


白天起來(PM22)後 在來跟大家討論了 lol~~
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 01:20:22
re:LionX
>因為 C++不允許部分授權
>所以 當A開發者將mA設為protected的話
>B開發者應該了解 A作者僅僅只想要授權只到繼承者來操作而已
>不然他public不就好了??

C++的protected就是完全授權,除非將來修改規則,不然就是這樣了。
既然是完全授權,要求"B開發者應該了解 A作者僅僅只想要授權只到繼承者來操作而已"
就不能"心想事成",要有實際行動才行。
當然,你說的在A的class中做充份的說明,也是一種實際行動的方法,但我覺得那是下策。
(工程師很容易便宜行事,結果可能只是狗吠火車而已)
雖然 C++ class 的 access specifier 不能做部份授權,但部份授權可以使用方法達到。
所以上策是把mA宣告成private,然後撰寫部份授權的方法成員。
這應也是C++設計時希望程式員遵循的模式。

個人的想法:如果要開一個class A 給普羅大眾繼承使用,
就不要有 protected 的資料成員(可以有protected 的函式成員)。
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 02:14:29
"如果說"這樣的Get不算破壞封裝:
class B: public A{
public :
int Get(){return mA;}
void Put(int iNew){mA=iNew;}
};
而這樣的Get是破壞封裝:
class B: public A{public : int *Get(){return &mA;}};
那麼指的就是C/C++指標的問題。
C/C++的指標本來就是既是天使也惡魔(令人又愛又恨)。
指標不小心使用,就很容易造成程式的漏洞。
如果class B: public A{public : int *Get(){return &mA;}};
造成class A問題,那麼應是屬於class B對指標的濫用,仍不是繼承之罪。
(我並不是說Get返回指標必然造成問題,這要看A設計的內容細節而定)
指標不小心使用造成的漏洞並不是只在class B的例子,隨處都可能遇到。
例如:
class A{
private:
 int iThief[1];
 int mA[10];
public: int* GetThief(){return iThief;}
};

void main()
{
A Aobj;
int iBooty[10];
int *iThief= Aobj.GetThief();
for (int i=0; i<11; ++i)
iBooty[i]= iThief[i+1];//<--這裡會破壞mA的封裝?
}
指標可以造成的破壞,也不限於類別之中,隨處都可以引爆。
指標可以說是程式核子彈!

要C/C++程式員不用指標,那是不可能的事。
簡單的說,把使用過指標的程式員全槍斃掉,
這世界就沒有寫C/C++的程式員了。
只能呼籲使用指標有三要:
一是小心,二小心,三還是小心。
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 02:57:30
弄一個比較具體的例子來探討好了

class A
{
protected:
  int i[2]; // 假設有某個理由須對子類別開放,但對外仍保護
public:
  A(int i1, int i2)
  {
    i[0] = i1;
    i[1] = i2;
  }

  virtual int Compute() = 0;
};

A 開放 i[] 給子類別,但最多只能在精神上期望子類別遵守不要把 i[] 開放給外界的規範,就算 A 的子類別 B 遵守規範,B 的子類別會遵守嗎?從 A 以下(包含 A)的子子孫孫任一個犯規,封裝就失敗了,我是從來不假設後繼者會遵守約定,至少在 C++ 語言的架構上可沒給你這樣的保障

至於 "繼承"為什麼要替大家擔下這個罪名?因在此的標題「繼承破壞封裝」不就是在討論正確封裝下是否能被後繼者破壞嗎

雖然「繼承破壞封裝」沒指明是要開放封裝的東西給後繼者,但唯有那些東西放在 protected 區段才可能有「繼承破壞封裝」的疑慮,也就是 class A 的情況,像是罪留子孫的意思 = ="

面對這個 class A 要怎麼用才好呢,組合 模式給了一個解決方案,如下的用法:

class B
{
protected:
  A *p; // 採用 組合 模式挽救 class A 會被破壞封裝的疑慮
public:
  void Set(A *A_Obj)
  {
    p = A_Obj;
  }
  virtual int Compute()
  {
    return p->Compute();
  }
};

也就是 A 的介面最可靠,就用這個介面就好,這樣 B 及 B 的子孫都沒那層疑慮

以下是使用範例

// 這是有遵守規範的好兒子
class C:public A
{
public:
  C(int i1, int i2)
    :A(i1,i2)
  {
  }
  virtual int Compute()
  {
    return i[0]+i[1];
  }
};

// 不肖子孫
class D:public A
{
public:
  D(int i1, int i2)
    :A(i1,i2)
  {
  }
  virtual int Compute()
  {
    return i[0]*i[1];
  }

  int *Get() // 很白目,繼承破壞封裝
  {
    return i;
  }
};

main()
{
  C C_Obj; // 老大還不壞,但仍帶有老爸的不良因子,後代可能會變壞
  D D_Obj; // 老二是壞兒子

  B Work; // 聰明的老爸事先做好了萬全準備

  // 不管誰來擔當重任,都沒機會使壞
  Work.Set(&C_Obj);
  cout << Work.Compute() << endl;

  Work.Set(&D_Obj);
  cout << Work.Compute() << endl;
 
}
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 04:46:37
re:cxxlman
>A 開放 i[] 給子類別,但最多只能在精神上期望子類別遵守不要把 i[] 開放給外界的規範,
>就算 A 的子類別 B 遵守規範,B 的子類別會遵守嗎?從 A 以下(包含 A)
>的子子孫孫任一個犯規,封裝就失敗了,我是從來不假設後繼者會遵守約定,
>至少在 C++ 語言的架構上可沒給你這樣的保障
好像最大的岐異在於protected成員是否"表示"子類別不應該把它再public出去。
你也知道的"C++ 語言的架構上可沒給你這樣的保障"。
既然C++的protected是對子類別"完全"授權,
就不能期望"子類別不應該把protected 成員再public出去"成為程式員的共識或通則。
我可以同意,大部份類別的protected成員,設計者大部份可能會希望子類別不要公開出去。
正如前面LionX提的,在class內作說明,但這僅有"道德勸說"的功能,不是正道。
正規方法還是把mA歸到private,再提供rotected的存取方法給子類別。
這樣就不用苦口婆心的"道德勸說"了^^

至於使用組合來解決所謂的"破壞"問題,我一直避開討論組合。
因為我覺得雖然在OOP會討論到組合,但組合並不算是OO的東西。
早在C的結構就已經再使用組合了。
所以使用組合來解決繼承的問題,在我看來是很奇怪的。
好吧!管它合不合適,只要能抓老鼠就是好貓。
如果組合算是一個解決的方法,但有一個吊詭的問題:
1.如果class A的開發者可以規範 class B的程式員使用組合來代替繼承;
2.那麼A的開發者也可以規範B的程式員不要寫會導致mA爆光的方法。
注意到1和2都是在"道德勸說"的層次,"道德勸說"可行,就1,2都可行。
1成立的話,那2也應成立。2如果成立,那就不需要1那麼麻煩了,繼承吧!

如果"道德勸說"不可行,進一步想:可不可能做出 class A 是不能被繼承的class?
這樣就不是道得勸說了,而是強迫class B非得使用組合的方法納入A(因無法繼承 A)。
答案是可行的!但因為C++沒有final class的設計,要做出final class(不能被繼承的class)
的對等功能得費不少手腳。所以個人覺得,王道還是:
把mA歸到private,再提供rotected的存取方法給子類別。簡單明瞭!
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 05:01:33
純娛樂:
class A{
protected: int mA;
};
既不希望 class A被繼承,而是使用組合邏輯。
那麼 protected的宣告看起來像不像色誘class B的程式員?^^
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 06:00:54
mA 最好都放在 private 中,會放到 protected 必是不得已(否則就是自找苦吃),這時下一步的防線就是把 class A 當介面用,後繼者都是實作類別,不要再用子類別了,也就是像組合的用法,這也不算是道德勸說,要算是避險吧
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 08:15:01
>mA 最好都放在 private 中,會放到 protected 必是不得已(否則就是自找苦吃),
>這時下一步的防線就是把 class A 當介面用,後繼者都是實作類別,
>不要再用子類別了,也就是像組合的用法,這也不算是道德勸說,要算是避險吧
看到上一篇的純娛樂嗎?
放到protected是不得已,但不給繼承要求使用組合避險?
protected只有在繼承時會有作用。
在不使用繼承情況下,那個protected和private作用是一樣。
怎麼個不得已法?
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 10:08:32

>>mA 最好都放在 private 中,會放到 protected 必是不得已(否則就是自找苦吃),
>>這時下一步的防線就是把 class A 當介面用,後繼者都是實作類別,
>>不要再用子類別了,也就是像組合的用法,這也不算是道德勸說,要算是避險吧
>看到上一篇的純娛樂嗎?
>放到protected是不得已,但不給繼承要求使用組合避險?
>protected只有在繼承時會有作用。
>在不使用繼承情況下,那個protected和private作用是一樣。
>怎麼個不得已法?

你那個娛樂版任意把 mA 開放給子類別叫做自找苦吃

要我一時之間去找一個不得已的例子還真找不出來, 我是假設 class A 開發者若不是在自找苦吃的情形下, 會把 mA 放在 protected 就是不得不為的, 那麼你要使用這個 class A 心裡要有避險的警覺, 它的子類別是有危險性, 為了安全起見只用 class A 這層就好, 當然 class A 是要被繼承的, 但不要直接用它的後繼者, 參照我上一個例子 class B 的用法, 其實這些都是很普遍的用法, 只是在不同角度的看法下, 有不同的見解而已

有時會被自己既有的想法困住, 一時走不出來, 抽根煙喝杯酒也許有幫助, 若是好好先生, 出去走走再回來想想吧


作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 11:07:25
>你那個娛樂版任意把 mA 開放給子類別叫做自找苦吃
誤會了!
我只是點出了protected是在宣告開放繼承者權限,又不希望有繼承者。
這其間之謬誤。

>要我一時之間去找一個不得已的例子還真找不出來,
proected 只有有繼承者時能發揮作用,不繼承就變成和private一樣。
所以應該是沒有不給繼承又不得不寫proected的例子。

要我硬拗,只能能說class A是老板寫的,沒有人敢改它。
軟體主管又不希望它的工程師繼承它出錯,所以搞了一個組合規則
給底下的工程師遵循。
但如之前說的,既沒辦法約束工程師規矩的撰寫子類別B,又怎能期望
可約束他們能乖乖的以組合來來替代繼承?
唯一可能就是,改寫 class A 為不能繼承的class,但這又要改寫老板的
class A...呵呵,不傷腦筋了^^
不談人的因素,回到純工程的討論:
要禁止子類別亂搞protected 資料成員,就不要protected;
既然寫了protected就要認知那是完全授權,不要管子類別會怎麼用。
(老爸給的錢都到兒子口袋了,就要要再管兒子怎麼花錢)
對子類別的撰寫,本來就應該充份理解某個成員資料為什麼是protected。
(不論是父類別或子類別的的protected成員)
要把protected的資料開放出去,是否合理,有其必要當然要三思而行。
不經思考的寫程式,程式一定漏洞百出,再多的組合也救不了。
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 11:41:14
to coco:

你一定沒看我寫的例子,例子中 class A 既有被繼承,且還故意讓後繼者 class D 去破壞封裝,然後用挽救者 class B 採用組合模式來 "繼承" class A 以挽救危機,組合模式從某一個角度看也是繼承

我先睡了,明天再繼續聊,晚安
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/19 下午 11:50:31
>為了安全起見只用 class A 這層就好,
只用到class A 這層的class 就是final class。
class A 是個final class 是要"做"出來,不是精神喊話( 要求使用組合我認為是精神喊話)

>當然 class A 是要被繼承的, 但不要直接用它的後繼者,
不懂意思...

>參照我上一個例子 class B 的用法, 其實這些都是很普遍的用法
組合常用啊!從C的結構就一直在用,但組合替代繼承?
這我就不知道了,我一直認為組合和繼承無關。

成見大家都有吧,但我自認腦筋還算有彈性(或許這正是我最大的成見,呵呵,反省反省...)
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 12:31:42
>你一定沒看我寫的例子,
我敢發誓,我有看^^

>例子中 class A 既有被繼承,且還故意讓後繼者 class D 去破壞封裝,
這是你希望"精神上"禁止的例子,不是嗎?難道你是要 class D 和 class B並用?

>然後用挽救者 class B 採用組合模式來 "繼承" class A 以挽救危機,
挽救者 class B既明知 class D 這樣做不好,為什麼不做乖寶寶 class C或class D1(class D乖寶寶版)
何以非用組合不可?
明知靠左開車很危險,那就乖乖的靠右開就好,何以非得直昇機代車來避開靠左開車的危險?
何況車子還可以改裝成只能靠右開的功能?

>組合模式從某一個角度看也是繼承
好吧!但我沒辦法想像。
我的看法是class A並沒有被繼承,class B 只是一個 class A 的介面。
是有這樣的用法,但我看過的都不是為了解決protected的繼承問題。
class B 被繼承,很難說服我它算是class A被繼承。
(和我知道的繼承定義不相符)
容我再龜毛的重複:
class B 的介面可以直接做在 class A 裡面,
class A 所有的資料成員宣告為private就好了。
這樣就可直接繼承A,也不用給class B仲介費了^^
(mA一定要宣告為protected又不給繼承是說不通的)

作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 02:30:54
容我在這再強調一次
預期使用者不遵守規範是不合理的
因為繼承者不遵守規範
那程式出問題會請他負責
再者假如A開發好完整系統正常在運作了
之後A離職了換B來接手
需要進行功能擴充了
B不遵守A預設的規範 然後導致系統出問題了
這個你覺得老闆會幹B還是A??
老闆會要B修還是把A叫回來修?
當然實際上B會全推給A 老闆會附和你然後叫你改
但心底絕對是 你不改沒事改了出事 然後還在推...
至於大家說的不能預期繼承者不亂來
這不就是隱含著 繼承破壞封裝 的意思了嗎??
因為繼承者可以亂來也可以不亂來
所以才有繼承破壞封裝不是
如同事先講的可以提供介面給繼承者操作mA
但是後續開發者亂搞勒?
class A
{
private:
int mA[2];
public:
void Set(int i1, i2){ mA[0] = i1; mA[1] = i2; }
}
A指預期讓後繼者使用者設定mA
繼承者覺得我想搞個mA的Get取出目前被設定的值
好吧你不開我自己搞
反正我看你A的宣告只有mA這參數
我來個
class B : public A
{
int *Get(){ return (int*)this; }
}
哈哈 看我多利害 指針在手 天下我有阿~~!!
那你叫A開發者怎麼辦?
請注意B使用了錯誤方法做了自認為正常的事
他Get可以取值 return mA[0]
這樣只是破壞了A預期的保護 但沒有太大危害
但是他傳出了mA的指針所以造成重大隱患
我想強調的一點是
不能因為通的過編譯就認為自己的方法是正常的
盡可能遵守原開發者的規範才是最正確的
就如同法律只是維持社會的最終防線
你不去違反他就不會對你進行逞罰
如同你不違反編譯器規範 他就不會讓你編譯失敗
但是還有一個叫倫理道德的規範在規範人的行為處世
你不遵守道德規範的確不會被逞罰
但是 也絕對不會有人欣賞你 還有人會在你背後對你指指點點
就如同你不遵守原開發者的規範
而自己胡搞瞎搞 就算程式正常運作
原開發者也不太敢在跟你在配合
捫心自問一下 如果你們逼不得已設計出了A那樣的類別
然後公司新人作後續開發給你來個int *Get(){ return mA; }
心底不OOXX的 我只能說你是佛心來的...
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 02:49:56

>弄一個比較具體的例子來探討好了
>
>class A
>{
>protected:
> int i[2]; // 假設有某個理由須對子類別開放,但對外仍保護
>public:
> A(int i1, int i2)
> {
> i[0] = i1;
> i[1] = i2;
> }
>
> virtual int Compute() = 0;
>};
>
>A 開放 i[] 給子類別,但最多只能在精神上期望子類別遵守不要把 i[] 開放給外界的規範,就算 A 的子類別 B 遵守規範,B 的子類別會遵守嗎?從 A 以下(包含 A)的子子孫孫任一個犯規,封裝就失敗了,我是從來不假設後繼者會遵守約定,至少在 C++ 語言的架構上可沒給你這樣的保障
>

這裡我想表達一下 精神上期望就是實際要求
如果繼承者不能遵守就不要繼承
試想一下參數檢驗這問題好了

//此函式進行a/b操作 其中b為分母不得為0
float Mod(float a, float b)
{
return a / b;
}

那請問一下 後續使用者不理說明
而硬來個 float s = Mod(1.86f, 0.0f);
請問這要怪誰??
那程式出問題了 老闆是罵你還罵他?
不要說Mod開發者必須先自己檢查分母是否為零
這個小程式他當然可以檢查
但是如果後續使用者也檢查了勒?
那不就變成重複檢查了?
小程式還可以 大程式的話一堆函式call來call去的
不先確認好檢查者是誰那效能耗費算誰的??
像這個檢查者確認(使用者確認或是開發者確認)
也僅僅是精神上的要求罷了
但是你可以不遵守嗎? 可以 但是 出錯你就得被罵...

>至於 '繼承'為什麼要替大家擔下這個罪名?因在此的標題「繼承破壞封裝」不就是在討論正確封裝下是否能被後繼者破壞嗎
>
>雖然「繼承破壞封裝」沒指明是要開放封裝的東西給後繼者,但唯有那些東西放在 protected 區段才可能有「繼承破壞封裝」的疑慮,也就是 class A 的情況,像是罪留子孫的意思 = ='

protected只是其中一部分 通常情況下的危害
只要有指標 有百百種方法來亂搞
所以 繼承破壞封裝 只是想強調他的潛在風險
雖然我個人是認為 這個論調 是把不合情的作法合理化

至於A罪留子孫 你當然可以心理OOXX他
但是繼承他你就得把他的精神保持下去

>
>面對這個 class A 要怎麼用才好呢,組合 模式給了一個解決方案,如下的用法:
>
>class B
>{
>protected:
> A *p; // 採用 組合 模式挽救 class A 會被破壞封裝的疑慮
>public:
> void Set(A *A_Obj)
> {
> p = A_Obj;
> }
> virtual int Compute()
> {
> return p->Compute();
> }
>};
>
>也就是 A 的介面最可靠,就用這個介面就好,這樣 B 及 B 的子孫都沒那層疑慮
>
>以下是使用範例
>
>// 這是有遵守規範的好兒子
>class C:public A
>{
>public:
> C(int i1, int i2)
> :A(i1,i2)
> {
> }
> virtual int Compute()
> {
> return i[0]+i[1];
> }
>};
>
>// 不肖子孫
>class D:public A
>{
>public:
> D(int i1, int i2)
> :A(i1,i2)
> {
> }
> virtual int Compute()
> {
> return i[0]*i[1];
> }
>
> int *Get() // 很白目,繼承破壞封裝
> {
> return i;
> }
>};
>
>main()
>{
> C C_Obj; // 老大還不壞,但仍帶有老爸的不良因子,後代可能會變壞
> D D_Obj; // 老二是壞兒子
>
> B Work; // 聰明的老爸事先做好了萬全準備
>
> // 不管誰來擔當重任,都沒機會使壞
> Work.Set(&C_Obj);
> cout << Work.Compute() << endl;
>
> Work.Set(&D_Obj);
> cout << Work.Compute() << endl;
>
>}

大大這比喻不好喔 B只是個聽話的使用者
B 跟A C D 是沒有繼承的關係的喔!
A才是 C D 的爸爸
B 只是一個 聚合 A 的對象而已
而C則代表他理解了A的要求 所以沒有問題
而D則代表他... A...恩...恩.....怪了我家低家法勒...
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 03:20:47

>to coco:
>
>你一定沒看我寫的例子,例子中 class A 既有被繼承,且還故意讓後繼者 class D 去破壞封裝,然後用挽救者 class B 採用組合模式來 '繼承' class A 以挽救危機,組合模式從某一個角度看也是繼承
>
>我先睡了,明天再繼續聊,晚安

組合從精神上不能算是一種繼承喔
從精神上他應該是一種使用關係
拿個H一點的解釋方式好了(女性同胞就把對象換成鴨吧 lol)
嫖妓----->依賴
包養----->聚合
結婚----->組合(現代應該算是聚合了)
當你有需要時 花錢嫖一下 需要時用一下 你也不用去管OOXX
只要符合你的標準 用完了你也不管她OOXX是吧?
這就叫依賴 依賴她來解決你部分問題
當然 [我拿青春賭明天 小費不給算強姦] 切記切記!!
當你看上一個辣妹 身材正點臉盤俏
不過考慮到內涵不足 單靠青春有保存期
結婚下去 投資報酬率太低 就可以用包養的
哪天你看她怎麼看都覺得沒以前那樣吸引你
或者你又看上了另一個身材比她正 臉盤比她俏
最重要的是 人家小姑娘還不懂事面 開價低
你不包她改包小姑娘 分手費給一給 請她回家吃自己
之後勒 你跟小姑娘每天愛來愛去的
她的死活你也就不聞不問 這就是叫做 聚合 ~!!
然後勒 幻想回到兩百年前
前面那小姑娘 嬌俏可愛 眼角帶俏
那聲音是一整個嬌滴滴的甜
你千辛萬苦 (參考周星X主演的 唐伯虎點秋香 有 含笑半步癲 那部)
終於用八人大轎 把人家抬回來了 ↑
沒想到從此~~!! (具體同樣請參照 ↑)
打牌沒你的份 吃飯還得躲到桌底下
最悽慘的是 連個床都不知道能不能上...
想離? 人家還叔叔伯伯爸爸媽媽爺爺奶奶
左鄰右舍街坊鄰居反正不管是認識不認識的
都哭喊著你想當陳世美~~
連死都要拖著你跟她同生共死~~這就叫組合關係...
你看以上都只是使用關係
嫖妓(依賴)是你有生理上需求時對她的使用
但是 你通常這次叫A下次叫B 不太會每次都要同一個
包養(聚合)也是你有生理上的需求
但是你對她合則聚不合則散 並不強迫她跟你陪葬
結婚(組合)也是你生(心)理上需求她
並且希望能跟她永永遠遠在一起 最好是同生共死
所以組合並不算是一種繼承喔
以上 LionX 不負責任講座完畢~~!!


作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 03:30:56
再來 有的人會想說
既然不准精神上不繼承
那編譯器幹麻不限制?
試想著法律跟倫理的關係
法律是屬於嚴格的限制逾越一不都是禁止的
道德是屬於寬鬆的規範你可以遵守也可以不遵守
編譯器開發者不能預期後續都不會有人需要有爭議的做法
所以他不限制但是希望大家自律
就像c內的goto不是也很希望大家不要去用
但是為什麼沒有取消它勒?
因為在某些場合他還是被需要的
特別提出來只是要求使用者必須確定
自己在做什麼 可能造成的後果
就如同dx在Sound的sdk的類別內就使用了goto方法
因為他清楚知道自己在做啥所以就沒問題了不是?
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 03:49:34
考慮到 上面那篇H版的關係介紹還是有混淆空間
所以這裡在發一篇正式一點的說明
我們通常都會對繼承作出一個依賴倒轉的要求
如果一個子類別不能在替代父類別後保持程式正常的話
我們就不認定它們符合繼承精神
當然也可以用上面提出的A C D B來曲解B跟A有繼承關係
但請問一下程式內如果有 A *pA = ???;
可以把A指針 C指針 D指針 放進去???內
但是一定沒辦法把B指針放進去
當然 有人會說 main內並沒有A指針 所以不會有問題阿
A指針已經被包在B內了
那這樣你不會覺得是B在物件內使用A來提供方法嗎??
然後講的細一點的話
C D繼承自A 所以實際上它們都包含著i[2]這個資料
所以實際上不管是A或C或D 它們this指向的都會是由i開頭的記憶體位址
但是B不繼承自A雖然實現相同的方法
但是B的this指向的卻是指向A類型的指針
這就好比 一隻小貓長個跟狗一樣 你不能就說牠是狗吧??
雖然牠一樣可以陪你玩 可以當你的暖爐...
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 10:30:20

>>為了安全起見只用 class A 這層就好,
>只用到class A 這層的class 就是final class。
>要class A 是個final class 是要'做'出來,不是精神喊話( 要求使用組合我認為是精神喊話)

抱歉,這裡語意上沒有表逹清楚
我的意思不是要讓 class A 成為 final class,是指由 class A 的延伸類別,使用端都轉形到 class A 來用

>>當然 class A 是要被繼承的, 但不要直接用它的後繼者,
>不懂意思...

就是上面那個解釋

>>參照我上一個例子 class B 的用法, 其實這些都是很普遍的用法
>組合常用啊!從C的結構就一直在用,但組合替代繼承?
>這我就不知道了,我一直認為組合和繼承無關。

我先上網找看看有沒有清楚的說明,找不到我再試著解釋看看,我怕說的不好

>成見大家都有吧,但我自認腦筋還算有彈性(或許這正是我最大的成見,呵呵,反省反省...)

"繼承破壞封裝" 這問題一開始也是被我的成見所困,和大家交流後突然頓悟,所以還得謝謝大家,雖然不清楚我的見解是否符合原意,但也算是可行的解釋
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 10:39:13
lionx 睡飽了,果然有精神 。
要消化你的萬言書還真得準備便當在電腦旁^^

>預期使用者不遵守規範是不合理的
>因為繼承者不遵守規範
>那程式出問題會請他負責
對!去除"人"的因素
只要protected寫的是合理。
繼承者要亂搞,干class A何事?

>class A
>{
>private:
>int mA[2];
>:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
>?好吧你不開我自己搞
>反正我看你A的宣告只有mA這參數
>我來個
>class B : public A
>{
>int *Get(){ return (int*)this; }
>}
>哈哈 看我多利害 指針在手 天下我有阿~~!!
咦?越來越像我的說法了(見前面thief的例子)^^
拉高視野看事情,就會發現破壞封裝干繼承何事!
破壞封裝的是指標(或參照),不是繼承。
class A{protected: int mA;};
class B:public A{
protected: int mB;
public:
int * GetA(){return &mA;}//<--繼承破壞封裝?
int * GetB(){return &mB;}//<--不是繼承照破不誤!
};
指標本來就是個很容易開後門,製造問題的東西。
我就一直想說的是:笨蛋!問題在指標不是繼承!
(沒有罵人的意思,希望不要引起情緒反應^^)

>組合從精神上不能算是一種繼承喔
呵,我又多一票了^^

>但請問一下程式內如果有 A *pA = ???;
>可以把A指針 C指針 D指針 放進去???內
>但是一定沒辦法把B指針放進去
這是其中一個理由。
所以我的看法組合B,從任何的角度看都不是繼承。
因為它只是個A的介面,壓根兒和A沒有血源關係。

咦?寫完了?怎麼沒抬到槓?
手有點癢,CC...
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 10:53:02
re:cxxlMan
>"繼承破壞封裝" 這問題一開始也是被我的成見所困,
>和大家交流後突然頓悟,所以還得謝謝大家,
>雖然不清楚我的見解是否符合原意,但也算是可行的解釋
為了反省自己的成見,剛剛google了和破壞封裝的關的文章。
有關繼承破壞封裝,有人討論,但沒有人說得出所以然來。
程設這裡還算是討論最多的地方:(
但找到幾篇有提到"破壞封裝"的論文,但指的都是friend
看來,我的成見又加深了^^
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 10:55:00
大家都好像糾結於A不該做出有危險的動作
而寄望於在後續的銜接上去遮蓋他的錯誤
但是 如果真的要搞破壞 真的能遮蓋住??
如果不搞破壞 那又何必把簡單的事複雜化勒?
講一個簡單的例子
開車發生車禍時 後車撞前車 不考慮其他因素
你直覺認為是誰的錯勒?
是不是是後車的錯?
因為他看的見前車 但前車不一定看的見他
寫程式也是一樣
我預期你該這樣用 你不照預期來我阻止不了你
但是我就不會為你背書
但是如果你照預期來作 那就是系統設計者要修改
所以我才會說ABCD這樣弄有點像拖褲子放屁
這樣的架構比較常用在
當對資料可能作不同樣的處理時
把處理方式獨立出來以後可以替換
而且試想A為什麼要把mA放在protected上
是不是就是覺得繼承者會直接去使用它
萬一這個預期是提供新的方法勒??
那你的全部只用A提供的介面操作不就掛點了?
例如A設計者規劃
class A
{
protected:
int mA[100];
.....
public:
int Get(int i){ return mA[i]; }
....
};
A設計者規劃了這樣的一個類別
但是他隱約聽到老闆說可能會需要查詢某值在那的位置
A心想了 靠都叫我明天別來了
把mA設在protected讓繼承者慢慢加功能吧
那你能期望A能提供那些不存在的功能嗎?
當然你可以修改A類別這是OK的
你也可以重寫A類別 這也看你高興~~
但是如果你也只是領薪水的 也沒有野心幹掉你頭上的
那加個註解 繼承下來擴充那不就解決了
後繼者亂搞 很簡單阿 看他是誰搞的就誰負責不是?
因為 A是A寫的 B是你寫的 C是他寫的
A掛了因為你沒搞過A所以你可以直接要老闆找A....
B是你寫的 掛了老闆會請你喝咖啡
C掛了 老闆找你? 你也可以直接要老闆找C~~~
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 11:00:44

>>
>>main()
>>{
>> C C_Obj; // 老大還不壞,但仍帶有老爸的不良因子,後代可能會變壞
>> D D_Obj; // 老二是壞兒子
>>
>> B Work; // 聰明的老爸事先做好了萬全準備
>>
>> // 不管誰來擔當重任,都沒機會使壞
>> Work.Set(&C_Obj);
>> cout << Work.Compute() << endl;
>>
>> Work.Set(&D_Obj);
>> cout << Work.Compute() << endl;
>>
>>}
>
>大大這比喻不好喔 B只是個聽話的使用者
>B 跟A C D 是沒有繼承的關係的喔!
>A才是 C D 的爸爸
>B 只是一個 聚合 A 的對象而已
>而C則代表他理解了A的要求 所以沒有問題
>而D則代表他... A...恩...恩.....怪了我家低家法勒...

好多問題我沒辦法一一回答,但這裡我要說明一下

class B 本來是要從 class A 繼承下來,因這裡是為了簡明而簡化的例子,看不出為什麼要繼承 A,所以就假設看成使用 A 這層介面對 B 是必要的,不管是使用 繼承 還是使用 組合。

至於 C 和 D 只是因 A 須要被繼承才能產生實體物件,有了實體物件才能提供 A 介面給 B 使用,因 B 只使用 A 介面,所以不管 C 和 D 會不會破壞封裝,都不會讓 B 或 B 的子孫隱藏破壞封裝疑慮
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 11:12:41

>lionx 睡飽了,果然有精神 。
>要消化你的萬言書還真得準備便當在電腦旁^^

XD 被發現了 凌晨都沒人陪我 只好自言自語了XD


>>預期使用者不遵守規範是不合理的
>>因為繼承者不遵守規範
>>那程式出問題會請他負責
>對!去除"人"的因素
>只要protected寫的是合理。
>繼承者要亂搞,干class A何事?
>
>>class A
>>{
>>private:
>>int mA[2];
>>:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
>>?好吧你不開我自己搞
>>反正我看你A的宣告只有mA這參數
>>我來個
>>class B : public A
>>{
>>int *Get(){ return (int*)this; }
>>}
>>哈哈 看我多利害 指針在手 天下我有阿~~!!
>咦?越來越像我的說法了(見前面thief的例子)^^
>拉高視野看事情,就會發現破壞封裝干繼承何事!
>破壞封裝的是指標(或參照),不是繼承。

當然更高層級面是可以指出是指標破壞封裝
但是會提出 繼承破壞封裝 是因為
B繼承自A所以他會有A的所有屬性
但是B不管是利用指標或者是protected內屬性
來作出不屬於A預期的操作
但是 在繼承體系之外的開發者
由於不包含也不知道A的屬性
就如同上面有人提出的ABCD言論
B只會知到A提供的方法
但是他不會知道A的屬性是吧
在假設A是繼承自W
那B就算看了A的宣告 除非他有W的宣告
不然他也只能知道A的定義吧?


>
>>組合從精神上不能算是一種繼承喔
>呵,我又多一票了^^
>
>>但請問一下程式內如果有 A *pA = ???;
>>可以把A指針 C指針 D指針 放進去???內
>>但是一定沒辦法把B指針放進去
>這是其中一個理由。
>所以我的看法組合B,從任何的角度看都不是繼承。
>因為它只是個A的介面,壓根兒和A沒有血源關係。

這裡我比較感覺是使用是代理

>咦?寫完了?怎麼沒抬到槓?
>手有點癢,CC...
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 11:21:12
>
>
>>
>>>組合從精神上不能算是一種繼承喔
>>呵,我又多一票了^^
>>

組合和繼承各有他們作用的領域,當然不能看成相同,但從資料的結構這角度來看,或是從實質面來看,他們是相當的
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 11:29:05
這就代表B是作為A的代理阿
那問題就來嚕??
如果A就是覺得繼承者一定會需要直接去操作mA
那這樣的代理不就沒有意義?
在程式設計語意上 代理 一詞很大部分就是一種限制的語句
他限制了使用者只能使用代理者提供的對象的部份功能
就如同你想要限制B的繼承者對mA的存取權
但是 繼承 這個東西是為了對擴充提供方便的東東
我很難理解大家為什麼要糾結在使用各種方法來防止後繼者出錯
我在前面都一直強調 繼承破壞封裝 是用不正確的寫法來質疑OO的錯誤
但是有人提出所以我就形容一下內容
之後大家用一大堆的方法來防堵這錯誤實際上我是覺得很沒必要
就如同函式與變數的命名 參數的檢查權 這些大家都知道依照規範
你不照規範 被抓出來就會被XXX
OO繼承也是一樣 不照規則就抓出來槍斃就好了
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 上午 11:40:13

>>
>>
>>>
>>>>組合從精神上不能算是一種繼承喔
>>>呵,我又多一票了^^
>>>
>
>組合和繼承各有他們作用的領域,當然不能看成相同,但從資料的結構這角度來看,或是從實質面來看,他們是相當的

不相當喔~~!!
資料結構上 繼承是包含員繼承者的所有資料
你用的B只包含A的指針
除非你說的組合是
class B
{
private:
A mA;
....
};
這才在資料結構上相等喔
但是這樣的話你怎麼拿CD去取代??
作者 : cheg(cheg)
[ 貼文 99 | 人氣 125 | 評價 410 | 評價/貼文 4.14 | 送出評價 24 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 12:01:55
封裝最基本的目的就是希望客戶端代碼不受影響

繼承會破壞封裝, 個人看法是同意上面大大說的
跟依賴的反轉有關係, 最典型的例子就是正方形
跟矩形的繼承, 如果單使用正方形或矩形, 不會
有奇怪的地方, 但是當多型介入的時候, 使用者
預期可以對矩形設定長跟寬, 但是丟正方形進去
就會吃鱉! 這符合我僅僅是做繼承而已沒有搞鬼
並且正方形跟矩形是各自自我滿足的!

所以不正確的繼承就會造成客戶的影響, 重點是
多型加繼承也是一種封裝, 它封裝了一整族型別

至於單純的實作繼承如何破壞封裝, 小弟也不甚清楚
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 12:05:45

>這就代表B是作為A的代理阿
>那問題就來嚕??
>如果A就是覺得繼承者一定會需要直接去操作mA
>那這樣的代理不就沒有意義?
>在程式設計語意上 代理 一詞很大部分就是一種限制的語句
>他限制了使用者只能使用代理者提供的對象的部份功能
>就如同你想要限制B的繼承者對mA的存取權
>但是 繼承 這個東西是為了對擴充提供方便的東東
>我很難理解大家為什麼要糾結在使用各種方法來防止後繼者出錯
>我在前面都一直強調 繼承破壞封裝 是用不正確的寫法來質疑OO的錯誤
>但是有人提出所以我就形容一下內容
>之後大家用一大堆的方法來防堵這錯誤實際上我是覺得很沒必要
>就如同函式與變數的命名 參數的檢查權 這些大家都知道依照規範
>你不照規範 被抓出來就會被XXX
>OO繼承也是一樣 不照規則就抓出來槍斃就好了

同樣的東西因應用的觀點不有不同的解釋,若 B 把 A 提供的功都一一對應給外界使用,這樣和 B 繼承 A 是不是相當
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 12:16:41

>
>>>
>>>
>>>>
>>>>>組合從精神上不能算是一種繼承喔
>>>>呵,我又多一票了^^
>>>>
>>
>>組合和繼承各有他們作用的領域,當然不能看成相同,但從資料的結構這角度來看,或是從實質面來看,他們是相當的
>
>不相當喔~~!!
>資料結構上 繼承是包含員繼承者的所有資料

先看看以下這說法你是不是能接受

class Child:private Parent
{
};



class Child
{
private:
  Parent p;
};

意思是一樣的,但 組合 強調的是

class Child
{
private:
  Parent *p;
};



>你用的B只包含A的指針
>除非你說的組合是
>class B
>{
>private:
>A mA;
>....
>};
>這才在資料結構上相等喔
>但是這樣的話你怎麼拿CD去取代??

以組合的基本意義來講,B 只能使用 A "介面",不是拿C D 去取代,而是只使用 C D 的 A "介面"
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 01:01:28

>
>>
>>>>
>>>>
>>>>>
>>>>>>組合從精神上不能算是一種繼承喔
>>>>>呵,我又多一票了^^
>>>>>
>>>
>>>組合和繼承各有他們作用的領域,當然不能看成相同,但從資料的結構這角度來看,或是從實質面來看,他們是相當的
>>
>>不相當喔~~!!
>>資料結構上 繼承是包含員繼承者的所有資料
>
>先看看以下這說法你是不是能接受
>
>class Child:private Parent
>{
>};
>
>和
>
>class Child
>{
>private:
> Parent p;
>};
>
>意思是一樣的,但 組合 強調的是
>
>class Child
>{
>private:
> Parent *p;
>};
>
>
>
>>你用的B只包含A的指針
>>除非你說的組合是
>>class B
>>{
>>private:
>>A mA;
>>....
>>};
>>這才在資料結構上相等喔
>>但是這樣的話你怎麼拿CD去取代??
>
>以組合的基本意義來講,B 只能使用 A '介面',不是拿C D 去取代,而是只使用 C D 的 A '介面'
>

關於組合的語意 可能需要你在上網查一下
保存指針在語意上是偏向聯合喔
而且不管是組合跟聯合都只能使用A的介面
再者我說的取代就是這個說法阿
繼承本來就是 下可以取代上
C D 都可以取代A的存在阿 我不覺得我的語意有錯也 Orz...
C D 去使用A的介面?? 使用的應該是B喔 = =...
我不是在跟你玩文字遊戲
但是你想表達的應該用B只是去使用C D 提供由A制定的介面
那我為何說是C D取代A勒?
因為你用A型指針去存放C D 的指針
不就是用C D去取代了A來作A該做的事情吧?
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 01:11:04
>同樣的東西因應用的觀點不有不同的解釋,
>若 B 把 A 提供的功都一一對應給外界使用,這樣和 B 繼承 A 是不是相當

那不就是B代理A 繼承是要求完全取代
代理就允許部份取代
繼承要求實現父類的所有功能並允許你增加功能
但是你不能對父類的功能進行縮減
但是代理可以 當然代理之後你可以在加入自己的功能
而且也可以不提供A的部份功能對吧?
硬要曲解合成與聯合都是一種繼承關係
這樣會讓新手從根本誤解繼承與代理這兩個的區別喔
當然如果你硬要認為B聚合A也算是繼承A
那我也只能笑笑 不過 這觀念 我個人實在是不太能認同
為什麼C++允許父指針存放子指針
就是因為他認定子類完全等同於父類
為什麼不允許存放合成對象指針
因為合成對象不能保證完全等同於父類
既使它們有相同的資料結構
(合成與繼承在特定狀況下是有相同的資料結構的)
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 01:20:34
>組合和繼承各有他們作用的領域,當然不能看成相同,
>但從資料的結構這角度來看,或是從實質面來看,他們是相當的
class B 作的跟A再相依它在電腦領域還是叫A 的 Interface,不能稱做相當於繼承自A。
LionX已經提出一個其中一個你很難反駁的子:
你可以:
class A *pA= Cobj;
但你不能這樣做:
class A *pA= Bobj;
即使你這樣做,編譯成功了,但它是一個比你想避開的問題更危險的程式:
class A *pA= static_cast<A *>(Bobj)
我想 class B 實質上是在做什麼,大家都了,所以不需辯論名詞問題,以免失焦。
回到問題的本質,其實我已提了多次,但每每失焦。
假設所謂的C繼承A(方法一)破壞封裝是成立的( 雖然我有意見,但為了討論就先假設它成立)
那麼使用A的介面B(方法二)就解決了問題嗎?
我認為沒有,因為(方法一)的這條路並沒有關閉。
你怎麼保證程式員只會走(方法二)不會走(方法一)?
這裡面的重點在於class A不是final class。
如果class A 是final class,那麼那個proteted變得完全沒意義,應該改為private。
沒了protected,所謂的繼承破壞封裝的原因不也消失了嗎?那還要(方法二)嗎?

LionX的繼承破壞封裝的例子:int *Get()
破壞是因指標而起,不是繼承,我也提出不用繼承也可以一樣的破壞封裝,不是嗎?
LionX自己也提出了指標的破壞是無所不在。
指標跟本防不勝防,只能從程式員的能力教育著手。
只要A本身是正確的class,那管得了繼承者亂搞?
class A{protected: int mA;};
class B:public A{
protected: int mB;
public:
int * GetA(){return &mA;}//<--就算你管得了 mA,那你管得了下面的mB嗎?
int * GetB(){return &mB;}//<--不是繼承照破不誤!
};
class B來說,mA和mB,雖然一個是繼承而來,一個是自有。
但手背手心都是肉兩個都是protected 成員,一樣會破壞。
class A的程式員想儘辦法防止protected成員被子類別破壞是沒有意義的。
怕子類別亂用,就用private,用了protected就表示不怕子類別亂用不是嗎?
(子類別亂用,也不是class A程式員的責任了)
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 01:21:34

>
>>
>>>
>>>>>
>>>>>
>>>>>>
>>>>>>>組合從精神上不能算是一種繼承喔
>>>>>>呵,我又多一票了^^
>>>>>>
>>>>
>>>>組合和繼承各有他們作用的領域,當然不能看成相同,但從資料的結構這角度來看,或是從實質面來看,他們是相當的
>>>
>>>不相當喔~~!!
>>>資料結構上 繼承是包含員繼承者的所有資料
>>
>>先看看以下這說法你是不是能接受
>>
>>class Child:private Parent
>>{
>>};
>>
>>和
>>
>>class Child
>>{
>>private:
>> Parent p;
>>};
>>
>>意思是一樣的,但 組合 強調的是
>>
>>class Child
>>{
>>private:
>> Parent *p;
>>};
>>
>>
>>
>>>你用的B只包含A的指針
>>>除非你說的組合是
>>>class B
>>>{
>>>private:
>>>A mA;
>>>....
>>>};
>>>這才在資料結構上相等喔
>>>但是這樣的話你怎麼拿CD去取代??
>>
>>以組合的基本意義來講,B 只能使用 A '介面',不是拿C D 去取代,而是只使用 C D 的 A '介面'
>>
>
>關於組合的語意 可能需要你在上網查一下

我說的組合是指 Design Patterns 的 Composite 模式,一般都叫組合吧

>保存指針在語意上是偏向聯合喔
>而且不管是組合跟聯合都只能使用A的介面
>再者我說的取代就是這個說法阿
>繼承本來就是 下可以取代上
>C D 都可以取代A的存在阿 我不覺得我的語意有錯也 Orz...
>C D 去使用A的介面?? 使用的應該是B喔 = =...
>我不是在跟你玩文字遊戲
>但是你想表達的應該用B只是去使用C D 提供由A制定的介面
>那我為何說是C D取代A勒?
>因為你用A型指針去存放C D 的指針
>不就是用C D去取代了A來作A該做的事情吧?

說的和聽的可能意思會有出入吧


作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 01:54:13

>>組合和繼承各有他們作用的領域,當然不能看成相同,
>>但從資料的結構這角度來看,或是從實質面來看,他們是相當的
>class B 作的跟A再相依它在電腦領域還是叫A 的 Interface,不能稱做相當於繼承自A。
>LionX已經提出一個其中一個你很難反駁的子:
>你可以:
>class A *pA= Cobj;
>但你不能這樣做:
>class A *pA= Bobj;

我才說是相當不是相等嘛,oop 是 oo 的工具,把眼界提高一點來看,繼承 和 組合 都是 oo 的工具,工具除了達到 oo 要的功能外,還會有工具本身的副加功能,繼承可以往上轉形(轉形到父類別),這點組合做不到,組合可以動態更換父類別(這點我最喜歡),這點繼承做不到

>即使你這樣做,編譯成功了,但它是一個比你想避開的問題更危險的程式:
>class A *pA= static_cast<A *>(Bobj)
>我想 class B 實質上是在做什麼,大家都了,所以不需辯論名詞問題,以免失焦。
>回到問題的本質,其實我已提了多次,但每每失焦。
>假設所謂的C繼承A(方法一)破壞封裝是成立的( 雖然我有意見,但為了討論就先假設它成立)
>那麼使用A的介面B(方法二)就解決了問題嗎?
>我認為沒有,因為(方法一)的這條路並沒有關閉。

因 A 提供給 外界 和給 子類別 的不一樣,B 所使用的只是 A 提供給外界的這層介面,不管是由 C 或 D 取得的,只要 B 不會使用到子類別這條路就行了,比如 B 就沒辦法用到 D::Get()

>你怎麼保證程式員只會走(方法二)不會走(方法一)?

這就是組合的威力,依組合基本定義只能使用到 A 提供給外界的介面

>這裡面的重點在於class A不是final class。
>如果class A 是final class,那麼那個proteted變得完全沒意義,應該改為private。
>沒了protected,所謂的繼承破壞封裝的原因不也消失了嗎?那還要(方法二)嗎?

沒錯

>LionX的繼承破壞封裝的例子:int *Get()
>破壞是因指標而起,不是繼承,我也提出不用繼承也可以一樣的破壞封裝,不是嗎?

不確定是否還有沒有其他,不過要能讓子類別能達到破壞的目的,這功能一定要在 protected

作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 02:04:42
>>你怎麼保證程式員只會走(方法二)不會走(方法一)?
>這就是組合的威力,依組合基本定義只能使用到 A 提供給外界的介面
唉!還是沒弄清我的意思。
我一再提的 class A 若不是final class
你怎麼防止class C 直接繼承 class A,而一定寫成繼承 class B(組合A)?
道德勸說嗎?
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 02:22:01

>>>你怎麼保證程式員只會走(方法二)不會走(方法一)?
>>這就是組合的威力,依組合基本定義只能使用到 A 提供給外界的介面
>唉!還是沒弄清我的意思。
>我一再提的 class A 若不是final class
>你怎麼防止class C 直接繼承 class A,而一定寫成繼承 class B(組合A)?
>道德勸說嗎?

class A 不可以是 final class, 因 A 有純虛擬函數, 要不然就沒有實體物件可用了


作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 02:49:04
>我說的組合是指 Design Patterns 的 Composite 模式,一般都叫組合吧

是阿 但你用的比較像聚合
組合跟聚合的界定很難區分
最重要的一點就是生命週期的不同
聚合意指生命週期可以不同
組合指生命週期相同
你使用保存指針的方式就沒辦法肯定生命週期相同吧?
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 02:55:27

>>>你怎麼保證程式員只會走(方法二)不會走(方法一)?
>>這就是組合的威力,依組合基本定義只能使用到 A 提供給外界的介面
>唉!還是沒弄清我的意思。
>我一再提的 class A 若不是final class
你怎麼防止class C 直接繼承 class A,而一定寫成繼承 class B(組合A)?
道德勸說嗎?

說明都寫了 規定都定了
不遵守自己扛不對嗎 = =??
法律定了你不遵守 結果 被抓
倫理定了你不遵守 結果 被白眼
就這樣阿
還是大家認為 強姦違反法律
所以 所有男性 性成熟後一律 OX上鎖
行房必須到派出所
讓員警確認女方是同意並成年的
在員警監視下解鎖並行房 行房完在鎖上去
以強制限制強姦的發生
這樣你覺得OK嗎
想想這樣說法 跟你們認為
A沒有強制讓繼承者無法操作mA不是一樣嗎?
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 03:02:10
>我才說是相當不是相等嘛,oop 是 oo 的工具,把眼界提高一點來看,繼承 和 組合 都是 oo 的工具,工具除了達到 oo 要的功能外,還會有工具本身的副加功能,繼承可以往上轉形(轉形到父類別),這點組合做不到,組合可以動態更換父類別(這點我最喜歡),這點繼承做不到

組合不能動態更換父類別 可以的是聚合
並且相當應該是指大致上一樣相等是全部一樣
就如同 A == B 那我們說 A等於B
如果是 A <= 0.0001 && A >= -0.0001 那我們可以說A相當於0.0
但你不能說A等於0對吧??
組合不等於繼承 並且我也認為他不相當於繼承
因為精神上不一樣
A <= 0.0001 && A >= -0.0001 是因為我們期望它近似於0
所以我們精神上希望它取代0
而繼承精神上是 依賴到轉 但組合並不能到轉 本質上根本不一樣

>這就是組合的威力,依組合基本定義只能使用到 A 提供給外界的介面

我們沒說組合不好 只是想強調組合不是種繼承
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 03:06:30

>>我說的組合是指 Design Patterns 的 Composite 模式,一般都叫組合吧
>
>是阿 但你用的比較像聚合
>組合跟聚合的界定很難區分
>最重要的一點就是生命週期的不同
>聚合意指生命週期可以不同
>組合指生命週期相同
>你使用保存指針的方式就沒辦法肯定生命週期相同吧?

是組合關係,例子中的程式為了方便表達,沒注要這些細節,B 姞束時應刪掉 p 才對
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 03:14:02
>是組合關係,例子中的程式為了方便表達,沒注要這些細節,B 姞束時應刪掉 p 才對

我說你的B跟A是聚合不是組合
不是指你程式內沒刪除 而是你這樣可以不刪除才對
但是組合是不可以不刪除的
所以我才會說你的例子是B聚合A
並且你隨時可以替換成繼承自A的任何物件對吧?
那你跟第一個傳入的A不是分別了??
那A跟B不就生命週期不同了不是?
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 03:21:11

>>我才說是相當不是相等嘛,oop 是 oo 的工具,把眼界提高一點來看,繼承 和 組合 都是 oo 的工具,工具除了達到 oo 要的功能外,還會有工具本身的副加功能,繼承可以往上轉形(轉形到父類別),這點組合做不到,組合可以動態更換父類別(這點我最喜歡),這點繼承做不到
>
>組合不能動態更換父類別 可以的是聚合
>並且相當應該是指大致上一樣相等是全部一樣
>就如同 A == B 那我們說 A等於B
>如果是 A <= 0.0001 && A >= -0.0001 那我們可以說A相當於0.0
>但你不能說A等於0對吧??
>組合不等於繼承 並且我也認為他不相當於繼承
>因為精神上不一樣
>A <= 0.0001 && A >= -0.0001 是因為我們期望它近似於0
>所以我們精神上希望它取代0
>而繼承精神上是 依賴到轉 但組合並不能到轉 本質上根本不一樣
>
>>這就是組合的威力,依組合基本定義只能使用到 A 提供給外界的介面
>
>我們沒說組合不好 只是想強調組合不是種繼承

繼承和組合當然兩種不同的東西,要說的適當還真不容易,就從使用端的觀點來看好了,當使用端拿到兩個物件,而這兩個物件一個是使用繼承做成的,另一個是使用組合做成的,但使用端對這兩個物件的操作方法和得到的結果都一樣,繼承和組合就是指這樣的開係,就說他們是可互替的開係好了
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 03:25:40
>繼承和組合當然兩種不同的東西,要說的適當還真不容易,就從使用端的觀點來看好了,當使用端拿到兩個物件,而這兩個物件一個是使用繼>承做成的,另一個是使用組合做成的,但使用端對這兩個物件的操作方法和得到的結果都一樣,繼承和組合就是指這樣的開係,就說他們是可>互替的開係好了

這樣的說法我就沒啥好挑剔的了XD
我只是針對你說的組合可以算是一種繼承
提出反駁罷了
不過這只能說我太龜毛了 呵呵
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 03:33:31

>>是組合關係,例子中的程式為了方便表達,沒注要這些細節,B 姞束時應刪掉 p 才對
>
>我說你的B跟A是聚合不是組合
>不是指你程式內沒刪除 而是你這樣可以不刪除才對
>但是組合是不可以不刪除的

依組合的定義,B 不是要和 A 共生嗎怎能不刪除

>所以我才會說你的例子是B聚合A
>並且你隨時可以替換成繼承自A的任何物件對吧?
>那你跟第一個傳入的A不是分別了??
>那A跟B不就生命週期不同了不是?

這有點為難了,依聚合定義 A 和 B 就不能同生共死吧,但這裡的 A 是必須要和 B 同生死的,你說要叫什麼好呢

作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 03:41:59

>
>>>是組合關係,例子中的程式為了方便表達,沒注要這些細節,B 姞束時應刪掉 p 才對
>>
>>我說你的B跟A是聚合不是組合
>>不是指你程式內沒刪除 而是你這樣可以不刪除才對
>>但是組合是不可以不刪除的
>
>依組合的定義,B 不是要和 A 共生嗎怎能不刪除

我說了 你的用法存在著可以刪除也可以不刪除
所以只能算聚合 聚合就是形容這樣不強制的結合關係

>
>>所以我才會說你的例子是B聚合A
>>並且你隨時可以替換成繼承自A的任何物件對吧?
>>那你跟第一個傳入的A不是分別了??
>>那A跟B不就生命週期不同了不是?
>
>這有點為難了,依聚合定義 A 和 B 就不能同生共死吧,但這裡的 A 是必須要和 B 同生死的,你說要叫什麼好呢

就是聚合阿 你喜歡可以讓它們一起死
你不喜歡可以拿個繼承自A的Z來取代你一開始傳入的C
然後C指針你不高興就刪掉 高興就讓他去一旁玩沙對吧?
當然你也可以執行到一半讓pA=NULL;
之後C去哪了天知道 ~~ 聚合就是指可以拋棄的關係
組合不是 組合是指不能拋棄的關係
所以我才會說
class B
{
private:
A mA;
........
};
這樣才叫做組合
因為A只能跟B一起死 你想拋棄還不行..
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 03:48:45

>
>>
>>>>是組合關係,例子中的程式為了方便表達,沒注要這些細節,B 姞束時應刪掉 p 才對
>>>
>>>我說你的B跟A是聚合不是組合
>>>不是指你程式內沒刪除 而是你這樣可以不刪除才對
>>>但是組合是不可以不刪除的
>>
>>依組合的定義,B 不是要和 A 共生嗎怎能不刪除
>
>我說了 你的用法存在著可以刪除也可以不刪除
>所以只能算聚合 聚合就是形容這樣不強制的結合關係
>
>>
>>>所以我才會說你的例子是B聚合A
>>>並且你隨時可以替換成繼承自A的任何物件對吧?
>>>那你跟第一個傳入的A不是分別了??
>>>那A跟B不就生命週期不同了不是?
>>
>>這有點為難了,依聚合定義 A 和 B 就不能同生共死吧,但這裡的 A 是必須要和 B 同生死的,你說要叫什麼好呢
>
>就是聚合阿 你喜歡可以讓它們一起死
>你不喜歡可以拿個繼承自A的Z來取代你一開始傳入的C
>然後C指針你不高興就刪掉 高興就讓他去一旁玩沙對吧?
>當然你也可以執行到一半讓pA=NULL;
>之後C去哪了天知道 ~~ 聚合就是指可以拋棄的關係
>組合不是 組合是指不能拋棄的關係
>所以我才會說
>class B
>{
>private:
>A mA;
>........
>};
>這樣才叫做組合
>因為A只能跟B一起死 你想拋棄還不行..

原來如此
我再確認一下,若 B 結束時 p 所指一定也要刪除,但 p 是可被替換,也算聚合嗎
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 03:58:01
>原來如此
>我再確認一下,若 B 結束時 p 所指一定也要刪除,但 p 是可被替換,也算聚合嗎

也算是阿 你在UML拉出一條Composition線
大家就會認定他們間是不可分離的結合
你拉出一條Aggregation大家就會知道那是一個存在替換關係的結合
例如 你在A跟B之間拉了一條Composition線
那大家就會認為A跟B是不可分割的
但是如果你拉了一個Aggregation線
那大家就會知道可以用A的子類來作取代
跟你要怎樣操作是沒關係的
因為A跟B必須一起死是Composition的充要條件
如果她們可以不一起死就不是
即使你現在是讓他們一起死
但是就像我上面所說的 如果你以後需要拿Z取代傳入的C
B並不會有任何負擔對吧?
而且你替換之後刪除掉C的話B也不會跟著死
不然你以為聚合跟組合作用差不多
幹麻多出他來對吧?
就是用來形容你這樣的使用關係的
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 04:04:21

>>原來如此
>>我再確認一下,若 B 結束時 p 所指一定也要刪除,但 p 是可被替換,也算聚合嗎
>
>也算是阿 你在UML拉出一條Composition線
>大家就會認定他們間是不可分離的結合
>你拉出一條Aggregation大家就會知道那是一個存在替換關係的結合
>例如 你在A跟B之間拉了一條Composition線
>那大家就會認為A跟B是不可分割的
>但是如果你拉了一個Aggregation線
>那大家就會知道可以用A的子類來作取代
>跟你要怎樣操作是沒關係的
>因為A跟B必須一起死是Composition的充要條件
>如果她們可以不一起死就不是
>即使你現在是讓他們一起死
>但是就像我上面所說的 如果你以後需要拿Z取代傳入的C
>B並不會有任何負擔對吧?
>而且你替換之後刪除掉C的話B也不會跟著死
>不然你以為聚合跟組合作用差不多
>幹麻多出他來對吧?
>就是用來形容你這樣的使用關係的

嗯嗯,了解了
現在換你了,我說的用聚合解決"繼承破壞封裝"的問題清楚了嗎
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 04:11:01
喔!小睡小會又多出了好多篇 ^^
不過看起來大部份又再討論組合聚繼承等名詞,
我就不加入戰局了,免得討論越來越失焦。

>>我一再提的 class A 若不是final class
>>你怎麼防止class C 直接繼承 class A,而一定寫成繼承 class B(組合A)?
>>道德勸說嗎?
>說明都寫了 規定都定了
>不遵守自己扛不對嗎 = =??
>法律定了你不遵守 結果 被抓
>::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
寫程序的法律,就是使用的編譯器所依循的語言規範(有強制約束力)。
程式員自訂的規矩要其它的程式員遵循,那是道德勸說(無強制約束力)。
我沒有說道德勸說不可行,但若道德勸說可行,class B(組合A)也沒有存在的必要了。
因為就直接道德勸說,寫class A的繼承類別的人不可以把protected的資料用指標
漏出去就行了。

作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 04:26:31

>喔!小睡小會又多出了好多篇 ^^
>不過看起來大部份又再討論組合聚繼承等名詞,
>我就不加入戰局了,免得討論越來越失焦。
>
>>>我一再提的 class A 若不是final class
>>>你怎麼防止class C 直接繼承 class A,而一定寫成繼承 class B(組合A)?
>>>道德勸說嗎?
>>說明都寫了 規定都定了
>>不遵守自己扛不對嗎 = =??
>>法律定了你不遵守 結果 被抓
>>::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
>寫程序的法律,就是使用的編譯器所依循的語言規範(有強制約束力)。
>程式員自訂的規矩要其它的程式員遵循,那是道德勸說(無強制約束力)。
>我沒有說道德勸說不可行,但若道德勸說可行,class B(組合A)也沒有存在的必要了。
>因為就直接道德勸說,寫class A的繼承類別的人不可以把protected的資料用指標
>漏出去就行了。

嗯嗯
這麼說你 繼承破壞封裝 和 解決辦法 搞懂了嗎
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 04:33:46
>>我一再提的 class A 若不是final class
>>你怎麼防止class C 直接繼承 class A,而一定寫成繼承 class B(組合A)?
>>道德勸說嗎?
>class A 不可以是 final class, 因 A 有純虛擬函數, 要不然就沒有實體物件可用了
 cxxlman 你累了嗎?小睡一會,至少喝杯咖啡吧^^
論述語言:"class A 若不是final class"表示底下說的是"A 不是final class"情況
就是因為A 不是final class,所以你沒辦法強制別人的classC是要繼承A還是你的B(組合)
只能道德勸說,也一提再提了,若道德勸說行得通,就直接道德勸說A的子類別不可以把
mA指標公開出去就好了。

就你寫的例子來說,不也存在著D會使壞的子嗎?
D要丟進work才安全,那還是我說的"道德勸說"(程式員不鳥你,也不會被罰錢)。
道德勸說真可解了問題,也不用遶圈子做class B就好了,不是嗎?
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 04:55:44
>>因為就直接道德勸說,寫class A的繼承類別的人不可以把protected的資料用指標
>>漏出去就行了。
>嗯嗯
>這麼說你 繼承破壞封裝 和 解決辦法 搞懂了嗎
從頭到尾,我認為LionX的例子是指標破壞封裝,和繼承沒有關係。
(例子舉得夠多了,不同意我也不想再舉了)
簡單的說純OOP裡面根不不會有指標這種東西(那OOP的實作之一C++才有)
若有人在OOP的討論裡,說"繼承會破壞封裝"時,講的一定不會是指標(因為OOP世界沒有指標)
其實午飯後我有網查一下相關的文章,我想整個議題根本就是烏龍一場。

是有一些文章提到"繼承有破壞封裝的疑慮",但都是一筆帶過。綜合起來所謂"繼承有破壞封裝的疑慮"
指的是protected成員(不論資料或方法)protected給繼承者,該成員有失去封裝的完整性。
怎麼說?成員開放給繼承者直接存取,對父類來說繼承類也是一種"外部",成員對外部開放不是破壞封裝是什麼?
好笑嗎?

有關class成員存取控制,是有一派認為不應
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 05:03:42
關class成員存取控制,是有一派認為根本不應該有protected。
這一派的人對protected會破壞封裝,所以根本不該使用protected。
接不接受這樣的論調個人可以選擇,反正不論如何程式都可以寫出來。
我是小部份接受啦。
例如,以前我建立一個class,預設是把資料成員設成protected。
覺得有必要時才把需要的成員設成private,這樣寫程式真的比較方便。
現在則是預設把資料成員設成private,等到子類別有合理的理由需要
直接存取時再把資料改為protected。
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 06:15:02
再從網路稍稍統計一下,發現提到"繼承破壞封裝"的十之八九都是在談java。
所以99%可確定"繼承破壞封裝"指的是當繼承時,破壞即已發生。不是指某個
函式返回指標所造成(java沒指標,對吧?)
推測C++少談的原因是有了指標這樣的怪物,那還怕protected這種小咖?
再整理一下結果:
子類別對父類別也是外界,可稱為小外。
父類別的protected成員對小外開放,有破壞封裝的疑慮。
畢竟真正的外界和小外還是有別(親戚和鄰居還是不同),
所以大部份說法都比較輕的語氣,如疑慮等字眼。
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 06:27:24
我再把例子弄的更簡明好了,有一個元件叫 CoolMan,他繼承自一個叫 CxxlMan 的介面,CxxlMan 介面如下

class CxxlMan
{
private:
  int mA;
protected: // 給子類別用的
  int *Get(); // 應標題 繼承破壞封裝 要求
 .....
public: // 給外界用的
  void Set(int);
 .....
};

我拿到了這個元件有兩個用法

  CoolMan *CM1 = new CoolMan; // 要小心使用
  CxxlMan *CM2 = new CoolMan; // 我只信任這介面^^

若純碎只是使用 CM2 是最安全的

但現在做一個元件叫 FuckMan,以擴增 CoolMan 的功能,但不管由 CxxlMan 還是 CoolMan 繼承,都得向 FuckMan 及 FuckMan 延伸類別開發者道德勸說,千萬別把 Get() 取得的位址讓外界知道,有沒有一勞永逸的辦法,只要這樣做就好:

class FuckMan
{
  CxxlMan *p; // 用 組合 模式,一樣只用到安全的介面
public:
  FuncMan() // Constructor
  {
    p = new CoolMan;
  }
  virtual ~FuncMan() // Destructor
  {
    delete p;
  }
  void Set(int) // 提供和 CxxlMan 相對的功能
  {
    p->Set();
  }
  ....
  ....
  void f(int); // 自己要擴增的功能
};

現在我的 FuckMan 元件只要提供和 CxxlMan 介面相對應的功能,或是把 p 讓外界知道也行
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 06:38:37

>>>因為就直接道德勸說,寫class A的繼承類別的人不可以把protected的資料用指標
>>>漏出去就行了。
>>嗯嗯
>>這麼說你 繼承破壞封裝 和 解決辦法 搞懂了嗎
>從頭到尾,我認為LionX的例子是指標破壞封裝,和繼承沒有關係。
>(例子舉得夠多了,不同意我也不想再舉了)
>簡單的說純OOP裡面根不不會有指標這種東西(那OOP的實作之一C++才有)
>若有人在OOP的討論裡,說"繼承會破壞封裝"時,講的一定不會是指標(因為OOP世界沒有指標)
>其實午飯後我有網查一下相關的文章,我想整個議題根本就是烏龍一場。
>
>是有一些文章提到"繼承有破壞封裝的疑慮",但都是一筆帶過。綜合起來所謂"繼承有破壞封裝的疑慮"
>指的是protected成員(不論資料或方法)protected給繼承者,該成員有失去封裝的完整性。
>怎麼說?成員開放給繼承者直接存取,對父類來說繼承類也是一種'外部',成員對外部開放不是破壞封裝是什麼?

好像你自己也說過,開放就不叫破壞吧

>好笑嗎?

>有關class成員存取控制,是有一派認為不應

本來我也覺得是在鬼扯, 不過當做是真的看也有和事實相符合的情形, 就當作往後要多注意一下的警愓吧, 快100篇文章, 大概沒人會有耐心看了吧
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 07:17:55
>>怎麼說?成員開放給繼承者直接存取,對父類來說繼承類也是一種'外部',
>>成員對外部開放不是破壞封裝是什麼?
>好像你自己也說過,開放就不叫破壞吧
是的,但"繼承有破壞封裝的疑慮"是建立在只有二元的立論基礎:
封裝只有開放和保護兩種,沒有半開放的這種東西。
protected 算是被保護的成員,繼承使得保護小小的破了功,這是第三態出現。
但如果封裝的立論基礎承認有半開放的第三態,那麼繼承就不算破壞封裝。

強調二元封裝的程式員使用有三態的C++等編譯工具,要實現二元封裝,
就是禁用protected。這是我提到有人提倡這種用法。對這些人來說,
繼承protected就是破壞封裝的行為(因為不承認半開放)。
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/20 下午 09:16:49
>我再把例子弄的更簡明好了,有一個元件叫 CoolMan,
>他繼承自一個叫 CxxlMan 的介面,CxxlMan 介面如下
>::::::::::::::::::::::::::::::::::::::::::::::::
>開發者道德勸說,千萬別把 Get() 取得的位址讓外界知道,
>有沒有一勞永逸的辦法,只要這樣做就好:
>::::::::::::::::::::::::::::::::::::::::::::::::::::::::
還是要道德勸說?
OK!但我認為這是試圖解決指標問題,不是繼承問題。
指標問題是堵得了這個,防不了那個。我提出你方案的
缺點,是否花更多的力氣來完善方案,就自行斟酌了。
(FuckMan我都改為FuncMan,以符普通級規定)
對於CoolMan來說繼承自CxxlMan,總是要增加點什麼東西吧!
但所有增加的東西都被視為不安全,所以FuncMan都不會去用。
這樣說法是你的意思吧?既是這樣,CoolMan又何必繼承自CxxlMan
再用FuncMan,來自癈武功?
CxxlMan有純虛擬的成員?
OK,純虛擬的成員需要在像CoolMan子類別中實現,是吧?
但用FuncMan的機制,不就是不信任CxxlMan的子類別介面嗎?
虛擬成員又開了後門,使得FuncMan有機會不自覺的去執行CoolMan的介面了。
夠複雜了,你若還有興趣再接力看怎麼解決吧。
沒興趣,就此打住吧。讓繼承者自已寫自己負責吧!
要管,就不要有protected。
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/21 上午 03:38:02
>嗯嗯,了解了
>現在換你了,我說的用聚合解決'繼承破壞封裝'的問題清楚了嗎

哈 我又睡醒了~~
你們說的我都知道也聽懂阿
但是我是老子派的
所以我不覺得我有必要這樣去防堵後繼者
我一向認為 只要註解明白了
大家就不會去作那些奇怪的事
那我還有必要上面提出的兩個動作?
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/21 上午 03:44:10

>>>因為就直接道德勸說,寫class A的繼承類別的人不可以把protected的資料用指標
>>>漏出去就行了。
>>嗯嗯
>>這麼說你 繼承破壞封裝 和 解決辦法 搞懂了嗎
>從頭到尾,我認為LionX的例子是指標破壞封裝,和繼承沒有關係。
>(例子舉得夠多了,不同意我也不想再舉了)
>簡單的說純OOP裡面根不不會有指標這種東西(那OOP的實作之一C++才有)
>若有人在OOP的討論裡,說"繼承會破壞封裝"時,講的一定不會是指標(因為OOP世界沒有指標)
>其實午飯後我有網查一下相關的文章,我想整個議題根本就是烏龍一場。
>
>是有一些文章提到"繼承有破壞封裝的疑慮",但都是一筆帶過。綜合起來所謂"繼承有破壞封裝的疑慮"
>指的是protected成員(不論資料或方法)protected給繼承者,該成員有失去封裝的完整性。
>怎麼說?成員開放給繼承者直接存取,對父類來說繼承類也是一種'外部',成員對外部開放不是破壞封裝是什麼?
>好笑嗎?
>
>有關class成員存取控制,是有一派認為不應

恩 這個論點我同意 聽到大大這樣說
我也發現我太侷限於C++上了
宏觀來看 OO的確是沒有指標的存在的
但是我還是不主張
為了某些規定 用強迫的手段讓他不能
而是明確的告訴他規範
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/21 上午 03:48:50
我覺得既然討論都已經到了這個階段
我想大家心底也都有一定的想法
也都也一定的收穫
再繼續爭論下去 實際上也不會再有太大結果
不如我們各自將各自對其他人的想法提出心得
在對自己的想法也提出心得
算是各自作出一個總結 來完結這篇討論 ^^
進入謾罵 或沒有結果的討論是最無趣的 XD
作者 : lionx(LionX)
[ 貼文 95 | 人氣 0 | 評價 270 | 評價/貼文 2.84 | 送出評價 7 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/21 上午 04:19:43
首先COCO大大在前文之中一直提倡的是
傳回protected屬性的參數指標 只能算是指標破壞封裝
而不能算是繼承破壞封裝
而繼承破壞封裝意指的是其他的意涵(目前並無定論)
並且COCO大大認為
防止protected屬性的參數指標被回傳而破壞封裝
最好的辦法就是不要使用protected屬性
上述在下提出的AB範例中
A根本不該將mA設定為protected
而是將其設為private並提供操作的介面
進而徹底防止後繼者對於該參數進行指標的操作
然後對於CxxlMan提出的ABCD範例認為
只要A的繼承還存在就不會有徹底防堵的一天
因為CD繼承A給B用
萬一日後有人亂搞了個Z給B用或只使用Z還是會產生破壞
對於CxxlMan大大強調的只能使用B
也只是道德勸說 並不存在強制力


然後CxxlMan大大 在上述在下提出的AB範例中
在確認A為不可變更下
對架構擴充為ABCD的範例
其中A不變CD為A的繼承者(一個使用指標破壞封裝(D)一個沒有(C))
然後提倡由代理者B來使用A提供的介面存取CD提供的方法
進而完全的避免後續對於mA的錯誤操作
並且CxxlMan大大強調
後繼者全部都只能繼承自B來操作A
這樣一來A的隱患就被B給封閉了


最後我認為指標是 繼承破壞封裝 的原因
但是在COCO大大最後的一文中提出
在宏觀的OO內是並不存在指標的
我思考了一下 認同並糾正了 以上的觀點
所以 事實上 我提出的AB例子應該是指標破壞封裝才對
再來對於指AB範例內指標破壞封裝的防治
我提倡的是做好說明來規範後繼者
讓後繼者不至於去曝露mA的指標給外部使用者
而不是利用強迫手段來防止
因為我認為就如同類別名稱 函式名稱 變數名稱 參數檢驗...等等
這些規範一樣 只要大家遵守 就OK
而不是預想大家都不遵守 所以我要 怎樣怎樣的因應
當你質疑你要繼承的對象類別
那你可以提出來要求原作者修改或是自己修改後讓他替換至整個系統
但是如果你一定要繼承他並且修改被駁回時
請將情緒不滿收藏在心底
然後依照繼承對象的規範來製作你的繼承類別
然後我並沒有針對COCO與CxxlMan大大的做法提出反駁
是因為我認為這兩個作法都是強制規範繼承者的方法
他們應該適用於系統規劃時期的規劃
但是我提出AB範例實際上想表達的是已經進入實作階段的內容
這代表著A是不可改的 並且系統要的是A的繼承者
當然拉 因為我都沒有提出這些所以讓大家搞混了 呵呵
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/21 上午 11:08:43
>>>怎麼說?成員開放給繼承者直接存取,對父類來說繼承類也是一種'外部',
>>>成員對外部開放不是破壞封裝是什麼?
>>好像你自己也說過,開放就不叫破壞吧
>是的,但'繼承有破壞封裝的疑慮'是建立在只有二元的立論基礎:
>封裝只有開放和保護兩種,沒有半開放的這種東西。
>protected 算是被保護的成員,繼承使得保護小小的破了功,這是第三態出現。
>但如果封裝的立論基礎承認有半開放的第三態,那麼繼承就不算破壞封裝。
>
>強調二元封裝的程式員使用有三態的C++等編譯工具,要實現二元封裝,
>就是禁用protected。這是我提到有人提倡這種用法。對這些人來說,
>繼承protected就是破壞封裝的行為(因為不承認半開放)。

  我覺得這要再修飾一下 "開放給繼承有破壞封裝的疑慮"
  真正的問題其實是 開放 兩個字
  目前都是假設有須要 開放 的情況在討論
  沒人能提出一個必須 開放 的真實例子吧
  也許根本不存在這樣的問題

  不管是二元或三態,若真有必須 開放 的情況
  問題依然會存在是吧
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/21 上午 11:57:24
>>我再把例子弄的更簡明好了,有一個元件叫 CoolMan,
>>他繼承自一個叫 CxxlMan 的介面,CxxlMan 介面如下
>>::::::::::::::::::::::::::::::::::::::::::::::::
>>開發者道德勸說,千萬別把 Get() 取得的位址讓外界知道,
>>有沒有一勞永逸的辦法,只要這樣做就好:
>>::::::::::::::::::::::::::::::::::::::::::::::::::::::::
>還是要道德勸說?

你把前面一大段文子裁掉了,我是說若用繼承才必須 道德勸說

>OK!但我認為這是試圖解決指標問題,不是繼承問題。
>指標問題是堵得了這個,防不了那個。我提出你方案的
>缺點,是否花更多的力氣來完善方案,就自行斟酌了。

我那個例子是指拿一個現成的 CoolMan 元件來用,不用花太多力氣

>(FuckMan我都改為FuncMan,以符普通級規定)
>對於CoolMan來說繼承自CxxlMan,總是要增加點什麼東西吧!
>但所有增加的東西都被視為不安全,所以FuncMan都不會去用。
>這樣說法是你的意思吧?既是這樣,CoolMan又何必繼承自CxxlMan
>再用FuncMan,來自癈武功?

這要看是要用哪一層介面,CxxlMan 相對於 CoolMan 是定義標準介面,CoolMan 去完善 CxxlMan 所要的機能,當然也會擴增功能和危險,若 FuckMan 要用 CoolMan 的擴增功能,就改成以下這樣

class FuckMan
{
  CoolMan *p; // 用 組合 模式,改成不安全的介面
public:

>CxxlMan有純虛擬的成員?
>OK,純虛擬的成員需要在像CoolMan子類別中實現,是吧?

這裡不特別指名有沒有,只是把 CxxlMan 視為要被使用,面對應用層的介面

>但用FuncMan的機制,不就是不信任CxxlMan的子類別介面嗎?

若 CxxlMan 不對子類公開封裝的東西,你要用哪一層介面都行,但為了符合討論的主題,所以 CxxlMan 有對子類別公開,所以不信任子類別

>虛擬成員又開了後門,使得FuncMan有機會不自覺的去執行CoolMan的介面了。

哈哈,這有意思了,CoolMan 就像病毒一樣,存心搞破壞了

>夠複雜了,你若還有興趣再接力看怎麼解決吧。

遇到這種存心做壞的元件,我也不知該怎麼辦

>沒興趣,就此打住吧。讓繼承者自已寫自己負責吧!
>要管,就不要有protected。

這點我有不同的看法,沒 protected 那麼那些 protected 的東西不就得改放到 public,只是把問題丟給 public 而已


作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/21 下午 01:55:03

>
>>虛擬成員又開了後門,使得FuncMan有機會不自覺的去執行CoolMan的介面了。
>
>哈哈,這有意思了,CoolMan 就像病毒一樣,存心搞破壞了
>
>>夠複雜了,你若還有興趣再接力看怎麼解決吧。
>
>遇到這種存心做壞的元件,我也不知該怎麼辦

這可能要徹底研究哪些動作叫做破壞封裝, 才能判斷虛擬函數會不會有破壞封裝的後門

以目前討論的傳回 mA 指標給外界算是破壞封裝, 除非這個虛擬函數有定義要傳回 mA 指標, 否則子類別還是沒能得逞
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/21 下午 03:51:30
我想三個人都想做個總結,但總有結不了感覺。
我再試圖總結一次好了^^

C++/Java 的類別設計有public/protected/private三種。
protected存取權限開放給子類別,但不開放給外界。
這種設計是把子類別視為一種"內部"的想法。
有一派理論認為子類別也是外界。(以下稱嚴格派),因為它和外界一樣,
父類別無法預期子類別會如何亂搞protected的資料成員。子類別既被視為外界,
當然會認為"protected 會破壞封裝"應該禁止。(這一派以下稱嚴格派)
嚴格派著文推"protected 會破壞封裝"時,並沒有把他們是基於"子
類別視為外界"這一點請清楚。所以也就造就成網路一堆人再問,但沒有人
說得清楚的情況(我看到的都沒答到核心)。

寫 C++ 的程式不用protected,程式還寫得下去嗎 ?當然可以,protected
本來就是基於方便性而已,不是必要性。
要不要用protected就自己看辦囉^^

re:CxxxlMan
>這點我有不同的看法,沒 protected 那麼那些 protected 的東西不就得改放到 public,
>只是把問題丟給 public 而已
不不不!所有的protected要改成private再用protected的介面提供給子類別使用。
這是嚴格派的理論,子類別也經由介面存取才能保護資料成員不被亂搞。而rotected的
介面也防止了外界對protected的存取。
一樣達到protected的目的。但就是比較不方便就是。
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/21 下午 04:02:49
後面回CxxxlMan好像漏了些東西,為免引起誤解重新整理一下:
re:CxxxlMan
>這點我有不同的看法,沒 protected 那麼那些 protected 的東西不就得改放到 public,
>只是把問題丟給 public 而已
不不不!所有的protected 資料成員要改成private,再用protected的介面(方法)
提供給子類別使用。
這是嚴格派的理論,子類別也經由介面存取才能保護資料成員不被亂搞。而rotected的
介面也防止了外界使用該介面對protected的資料成員存取。
一樣達到protected的目的。但就是比較不方便就是。
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/21 下午 08:57:42

>
>re:CxxxlMan
>>這點我有不同的看法,沒 protected 那麼那些 protected 的東西不就得改放到 public,
>>只是把問題丟給 public 而已
>不不不!所有的protected要改成private再用protected的介面提供給子類別使用。
>這是嚴格派的理論,子類別也經由介面存取才能保護資料成員不被亂搞。而rotected的
>介面也防止了外界對protected的存取。
>一樣達到protected的目的。但就是比較不方便就是。

我還以為是要把 protected 拿掉, 就是不要對外界, 對子類別開放資料就對了,
其實這個標準制定組織只要一聲令下就可立定站好了,
目前只能靠自己自律囉
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/22 上午 09:19:04
>我還以為是要把 protected 拿掉, 就是不要對外界, 對子類別開放資料就對了,
對!抱歉沒說的清楚。
二分法封裝是針對資料成員說的。
封裝後的資料成員,本來就是可以(也是必需)透過方法公開給外部操作。
公開的方法就是介面,只公開給子類別的介面,就是protected介面。
這是嚴格派的完成意思。

>其實這個標準制定組織只要一聲令下就可立定站好了,
>目前只能靠自己自律囉
問題在於這樣的論點並不是共識,只是一部份人的堅持。
我覺得是有一點道理,但也只是小部份接受。
若這成了大多數的共識,也許新的OOP會制訂出資料成員只有私有和公有兩種。
V++/Java自然會出現新的版本。
那時...我就算只有小部份接受,也只能遵守了(不然編譯過不了,程式就寫不成了^^)
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/22 上午 09:32:20
如果嚴格派也看是一種進化。
那再進化的話,也許資料成員應該只有私有一種!
外界要操作資料,一律請透過介面!
這樣也許更符合封裝的精神 ^^
不過這也許可以在java或新的oop實作實現。
C++不太可能的,如之前提的:
有了指標的怪物,那還怕protected資料這種小咖!
制不了指標,封裝嚴格化的結果只是:
抓了小的放了大的,沒太大意思。
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/22 下午 02:41:26
若要徹底防止破壞封裝,那麼像 int *get(); 這樣的成員函數都不應該存在。

但這會引發另一個難題,若有這樣的須求要怎麼辦?比如物件共享,喔喔,我好像找到一個必須開放的實際例子了。

現在的情況是要防止破壞封裝,就沒辦法有共享功能,要有共享能力,就沒辦法防止破壞封裝,怎麼辦?

只好以最大的聯集為準,也就是要共享放棄封裝,整個態度由原本擁謢封裝,盡一切力量防堵破壞的行為,變成封裝是不值得信賴應該丟掉的東西,也就是不能再把自己擁有的屬性總是看成一直不變,天啊!

因應這樣的局勢只好再往後退到下一步防線,至少在我使用期間不要給我亂改吧,也就是同步控制。

才幾天時間,世界整個變了一個樣 = =



作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/22 下午 04:03:53
>若要徹底防止破壞封裝,那麼像 int *get(); 這樣的成員函數都不應該存在。
>但這會引發另一個難題,若有這樣的須求要怎麼辦?比如物件共享,
>喔喔,我好像找到一個必須開放的實際例子了。
指標在強調安全的程式語言,絶對是一個魔鬼。
沒有指標,程式還是一定寫得下去(不會到必需這麼嚴重)。
但就是會少了很多的方便性。
但要C/C++程式員放棄指標,100個有99.9個人不願意;
若要用C/C++寫firmware的人放棄指標,100個會有101個人不願意。
int *get(); 本來我就不認為它是一種破壞(至少從上面的例子上看不出來)。
有很多collection的例子,會提供buffer的指標給外部使用,主要是
要應付極端的速度要求。但在這種情況也還是可以有安全措施:
int *get()把buffer lock起來(別人不能再get也不能作相關的操作)直到unlock。
所以函式應改成配對:
int *Lock();//就是get
int *Unlock();//可以視為 put back
像MFC的CArray就有提供把內部buffer暴露的函式:GetData
可惜的是MFC並沒有作相關的保護措施,只有在使用說明作道德勸說 :(

>現在的情況是要防止破壞封裝,就沒辦法有共享功能,要有共享能力,就沒辦法 防止破壞封裝,怎麼辦?
共享資料,大部份都是共享提取,不是共享改變(共享改變會延伸更複雜的問題)
若只是共享提取, const int *get(); 就可解決。
若真的想共享改變,透過介面還是可以作,只是少了方便性和速度。
不考慮速度,單從邏輯看,資料完全私有封裝是可行的。
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/22 下午 07:19:40
>
>>現在的情況是要防止破壞封裝,就沒辦法有共享功能,要有共享能力,就沒辦法 防止破壞封裝,怎麼辦?
>共享資料,大部份都是共享提取,不是共享改變(共享改變會延伸更複雜的問題)

我說的共享指的是完全的共享功能, 可讀可寫可吃掉

>若只是共享提取, const int *get(); 就可解決。

若真的要發放外界知道, 這方法是比較好的方法, 比道德勸說要有力一點

>若真的想共享改變,透過介面還是可以作,只是少了方便性和速度。
>不考慮速度,單從邏輯看,資料完全私有封裝是可行的。

後來再想想, 共享應只在 物件 上, 基本形別的東西不應拿來共享, 因它沒內建同步控制的機制, 至少 C++ 沒有, 只聽說過有 物件共享 沒聽說有 變數共享 吧, 所以基本形別的資料還是應安全的封裝好, 哈哈, 繞了一圈又回到原點 ^^
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/22 下午 09:37:30
>後來再想想, 共享應只在 物件 上, 基本形別的東西不應拿來共享,
>因它沒內建同步控制的機制, 至少 C++ 沒有, 只聽說過有 物件共享
>沒聽說有 變數共享 吧, 所以基本形別的資料還是應安全的封裝好,
>哈哈, 繞了一圈又回到原點 ^^
 快變成嚴格派了 ^^
OOP的世界,基本形別的資料也是物件喔。不應另眼相待!
要封就一視同仁封吧!
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1042 | 人氣 3227 | 評價 1260 | 評價/貼文 1.21 | 送出評價 28 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2011/2/23 下午 12:06:14

>>後來再想想, 共享應只在 物件 上, 基本形別的東西不應拿來共享,
>>因它沒內建同步控制的機制, 至少 C++ 沒有, 只聽說過有 物件共享
>>沒聽說有 變數共享 吧, 所以基本形別的資料還是應安全的封裝好,
>>哈哈, 繞了一圈又回到原點 ^^
> 快變成嚴格派了 ^^
>OOP的世界,基本形別的資料也是物件喔。不應另眼相待!
>要封就一視同仁封吧!

要成為可共享的物件, 必須要做到兩件事, 1. 要有決定生存機制(比如用計數器) 2. 要有同步控制的機能 , 這些不能放到基本形別中, 只能由宿主提供, 一旦曝光就繞過宿主提供的這些功能

說到計數器, 又讓我想到一個破壞封裝的實例, 就是微軟的 COM 元件, 它把計數器的操作函數交給外界真是一大失策, 應該封裝起來, 只能由 CComPtr 處理, 並且強制 COM 元不能單獨使用, 一定要和 CComPtr 搭配使用, 這樣做才是王道
 板主 : simula
 > C++ - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - C++ - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
C++
1 Raymond 13050 
2 青衫 4760 
3 simula 4690 
4 coco 4030 
5 白老鼠(Gary) 3670 
6 ozzy 2540 
7 Ben 2250 
8 Anderson 1960 
9 windblown 1650 
10 Kenny 1560 
C++
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2019 程式設計俱樂部 http://www.programmer-club.com.tw/
0.609375