weidagang2046的專欄

          物格而后知致
          隨筆 - 8, 文章 - 409, 評(píng)論 - 101, 引用 - 0
          數(shù)據(jù)加載中……

          C++容許private方法是virtual是不是一個(gè)漏洞

          發(fā)信人: eastcrusader (昨我已逝), 信區(qū): CPlusPlus
          標(biāo)  題: [合集] C++容許private方法是virtual是不是一個(gè)漏洞
          發(fā)信站: 水木社區(qū) (Fri Aug  5 09:36:12 2005), 站內(nèi)

          ☆─────────────────────────────────────☆
             Arnald (墮落獸人) 于  (Wed Aug  3 10:34:22 2005)  提到:

          如下面的代碼,輸出是
          Base::doPublic
          Derived::doPrivate
          這樣豈不是可以讓讓一個(gè)子類冒充父類的private成員函數(shù),不過好像一般private不會(huì)也沒有必要聲明為virtual


          //main.cpp
          #include <stdio.h>

          class Base
          {
          public:
            void virtual doPublic()
            {
              printf("Base::doPublic\n");
              doPrivate();
            }

          private:
            void virtual doPrivate()
            {
              printf("Base::doPrivate\n");
            }
          };

          class Derived : public Base
          {
          private:
            void doPrivate()
            {
              printf("Derived::doPrivate\n");
            }

          };

          int main()
          {
            Base *b = new Derived();
            b->doPublic();
          }



          ☆─────────────────────────────────────☆
             eastcrusader (昨我已逝) 于  (Wed Aug  3 10:59:30 2005)  提到:

          這個(gè)不存在什么漏洞,也沒有冒充的問題。C++中,除了構(gòu)造函數(shù)內(nèi)包含的虛函數(shù)調(diào)用是
          早綁定(其他還有沒有特殊情況一時(shí)記不起來),其他的虛函數(shù)調(diào)用都是晚綁定,也就是說,你在Derived 類中調(diào)用的時(shí)候,實(shí)際(this)也是函數(shù)調(diào)用的一個(gè)參數(shù),和this指針有關(guān)的
          vtable中也包含了private和protect部分的虛函數(shù)指針,vtable中的指針指向誰就是誰,責(zé)任明確,分工清楚,那來得冒充問題呢?




          ☆─────────────────────────────────────☆
             Arnald (墮落獸人) 于  (Wed Aug  3 11:10:00 2005)  提到:

          我覺得還是一個(gè)漏洞,這么說吧
          有一個(gè)父類Account,有一個(gè)public方法doTransaction,有一個(gè)virtual private方法transfer(int money),doTransaction里面調(diào)用了transfer(1000),transfer的工作就是轉(zhuǎn)帳1000塊錢。
          我要是有一個(gè)子類MyAccount,也定義了一個(gè)virtual private transfer(int money),但是轉(zhuǎn)帳額度是moneyX2
          Account *a = new MyAccount();
          a->doTransaction();
          組后調(diào)用的是子類MyAccount的transfer,這樣就轉(zhuǎn)了2000塊錢,而不是本來的1000塊錢,發(fā)了:)

          java可能意識(shí)到這個(gè)問題,所以private方法,默認(rèn)是final的,也就是private方法就是靜態(tài)綁定的。








          ☆─────────────────────────────────────☆
             boost (阿布) 于  (Wed Aug  3 11:21:52 2005)  提到:

          要出錯(cuò)也是用的人出錯(cuò)。。這不是純屬活該嘛。。




          ☆─────────────────────────────────────☆
             ilovecpp (cpp) 于  (Wed Aug  3 11:22:36 2005)  提到:


          如果doTransaction()本身就是virtual function,派生類直接override它轉(zhuǎn)2000塊錢,
          你是否也認(rèn)為是漏洞?





          ☆─────────────────────────────────────☆
             Arnald (墮落獸人) 于  (Wed Aug  3 11:38:29 2005)  提到:

          我剛才打了比方1000塊
          如果doTransaction大概是這樣的工作順序
          void doTransactio(User user, int money)
          {
             if ( checkUserBalance(user) >= money)) //檢查用戶余額夠不夠
             {
                transfer(money);
             }
          }
          checkUserBalance也是priavte的成員方法,用戶余額只有1200塊了,正常情況下doTransaction(user, 2000)肯定失敗了,但是通過重載transfer轉(zhuǎn)帳兩倍,checkUserBalance時(shí)查的是1000,實(shí)際轉(zhuǎn)了2000。










          ☆─────────────────────────────────────☆
             ilovecpp (cpp) 于  (Wed Aug  3 11:43:45 2005)  提到:


          如果doTransaction本身就是virtual function呢?我在派生類中直接把if給去掉。
          你是否認(rèn)為virtual function都是漏洞?



          ☆─────────────────────────────────────☆
             jasss (robot) 于  (Wed Aug  3 12:06:15 2005)  提到:


          :我覺得還是一個(gè)漏洞,這么說吧
          :有一個(gè)父類Account,有一個(gè)public方法doTransaction,有一個(gè)virtual private方法
          :transfer(int money),doTransaction里面調(diào)用了transfer(1000),transfer的工作就是
          :轉(zhuǎn)帳1000塊錢。
          :我要是有一個(gè)子類MyAccount,也定義了一個(gè)virtual private transfer(int money),但
          :是轉(zhuǎn)帳額度是moneyX2
          :Account *a = new MyAccount();
          :a->doTransaction();
          :組后調(diào)用的是子類MyAccount的transfer,這樣就轉(zhuǎn)了2000塊錢,而不是本來的1000塊錢,
          :發(fā)了:)
          :

          Here you saw it as a serious hole, but someone else saw it as a 
          great "feature"... :)

          Actually using virtual and private access control, we can construct
          the well-known pattern -- Template Method, which was illustrated by GOF...

          In your example, the doTransaction is the template method, which defines 
          the skeleton of an algorithm, and the virtaul private transfer function 
          (and other functions if necessary) is/are the concrete inner steps, and 
          these steps can be changed later (in derived classes) without touch the 
          template method itself...

          So you see the private control can encapsule not only data member, but
          also algorithm implementations, isn't this useful enough for you?






          ☆─────────────────────────────────────☆
             Arnald (墮落獸人) 于  (Wed Aug  3 12:10:32 2005)  提到:

          好吧,Account里面的doTransaction這樣
          void doTransaction(User user, int money)
          {
             Token *token = getSessionToken(user, currentTime);
             transfer(money, token);
          }
          getSessionToken是父類Account的private方法,作為子類的MyAccount,沒有辦法獲得這個(gè)token,getSessionToken返回一個(gè)類似令牌的東東驗(yàn)證身份,每次操作transfer必須帶上這個(gè)token。









          ☆─────────────────────────────────────☆
             Arnald (墮落獸人) 于  (Wed Aug  3 12:22:02 2005)  提到:





          如果要實(shí)現(xiàn)template pattern,可以把希望子類重載的成員聲明成protected啊
          Java禁止private作為virtual,一樣也可以實(shí)現(xiàn)template pattern





          ☆─────────────────────────────────────☆
             ilovecpp (cpp) 于  (Wed Aug  3 12:28:24 2005)  提到:


          你沒有理解我的意思。子類和父類要保持IS-A關(guān)系,子類必須滿足父類的所有invariants。
          然而,overridding機(jī)制本身不能保證這一點(diǎn)。override掉父類的任何一個(gè)方法,都有可能
          破壞invariant。所以你看,這不是private或者public的問題,這是virtual的固有問題。

          就你那個(gè)例子,我的doTransaction()為什么要調(diào)用transfer()? 我可以做任何事,我
          甚至可以delete this。

          你需要的,是能表達(dá)invariant/constraint的語言。禁止virtual private不會(huì)帶來什么。



          ☆─────────────────────────────────────☆
             ilovecpp (cpp) 于  (Wed Aug  3 12:50:47 2005)  提到:


          That virtual function is intended to be implemented, not called, by the 
          derived class.  Protected would be the wrong visibility, and doesn't
          well communicate the intention.





          ☆─────────────────────────────────────☆
             Arnald (墮落獸人) 于  (Wed Aug  3 13:10:40 2005)  提到:

          的確沒有理解你的意思
          這么說吧,一個(gè)private的方法,按說只能夠被自己這個(gè)類的方法調(diào)用
          現(xiàn)在private方法可以是virtual的,也就導(dǎo)致有的情況下,private方法可以被不是這個(gè)類的方法調(diào)用
          這樣,不和private的初衷矛盾嗎







          ☆─────────────────────────────────────☆
             ilovecpp (cpp) 于  (Wed Aug  3 13:20:24 2005)  提到:


          Base::private_method()自然只能被Base的方法調(diào)用。



          ☆─────────────────────────────────────☆
             Arnald (墮落獸人) 于  (Wed Aug  3 13:43:08 2005)  提到:

          我的Derived方法里的private方法,卻被Base的public方法調(diào)用了






          ☆─────────────────────────────────────☆
             longda (longda) 于  (Wed Aug  3 13:43:27 2005)  提到:

          總覺得這個(gè)討論比較沒有意義。干嘛要把你不想被子類改的聲明為virtual,還有private方法就是子類不能調(diào)用啊,變成了virtual也一樣。





          ☆─────────────────────────────────────☆
             ilovecpp (cpp) 于  (Wed Aug  3 13:48:19 2005)  提到:


          what's bad with that?  it's *you* who made it "virtual".



          ☆─────────────────────────────────────☆
             Arnald (墮落獸人) 于  (Wed Aug  3 13:55:40 2005)  提到:

          ok,我看到c++和java對(duì)private方法能不能夠是virtual上有差異
          java比C++出現(xiàn)的晚,有意的不容許private是virtual肯定是java語言的發(fā)起者覺得C++這個(gè)特性不適合java

          如果程序員有意識(shí)的不個(gè)private方法弄成virtual的,兩者沒有區(qū)別
          就此結(jié)貼,不再討論






          ☆─────────────────────────────────────☆
             ilovecpp (cpp) 于  (Wed Aug  3 14:05:35 2005)  提到:


          please note that java methods are by default "virtual".  it must be
          very bad in c++ if all your private methods are virtual, LOL.




          ☆─────────────────────────────────────☆
             Arnald (墮落獸人) 于  (Wed Aug  3 14:15:07 2005)  提到:


          In java, non-private methods are by default "virtual".
          private methods are by default "final".






          ☆─────────────────────────────────────☆
             ilovecpp (cpp) 于  (Wed Aug  3 14:38:35 2005)  提到:


          Yeah, they picked "virtual" as the default, and then found that it's 
          a really bad choice for private methods.  "Ok, let's make a special
          case.  Private methods should default to 'final'."  But there is no
          keyword "virtual" in java, so you can't override the default. oops...

          Moral of the story: choose defaults really carefully.




          ☆─────────────────────────────────────☆
             Arnald (墮落獸人) 于  (Wed Aug  3 14:57:38 2005)  提到:

          So, you believe that it is a defect about Java that *private* method cannot be *virtual*?

          I believe that they did it on purpose.






          ☆─────────────────────────────────────☆
             ilovecpp (cpp) 于  (Wed Aug  3 15:07:42 2005)  提到:


          Not exactly a defect.  It's about favourring one less keyword (virtual) over
          one more (not exceedingly important) function (overridding private methods).
          Reasonable choice, if you must have non-private methods default to non-final.


          Oh, you can ask Gosling. (He's coming China)
          There's no D&E for Java so that's the only way...



          ☆─────────────────────────────────────☆
             Arnald (墮落獸人) 于  (Wed Aug  3 15:27:20 2005)  提到:



          OK. He must have some idea-:)

          What does "D&E" stand for?



          ☆─────────────────────────────────────☆
             supercloud (飛云) 于  (Wed Aug  3 15:43:38 2005)  提到:


          a本來就是子類的指針,當(dāng)然調(diào)用子類的transfer,有什么問題嗎?





          ☆─────────────────────────────────────☆
             jasss (robot) 于  (Wed Aug  3 16:29:14 2005)  提到:


          Sorry for the late response, was absent just now...


          Well, of course you can make your transfer function 
          a protected member function, but is this really you want?
          Do you really want to call the base class's transfer
          function in your derived class? It is hardly possible 
          since the purpose of the derived class is replace the 
          algorithm implementation... 

          So, in my mind they should be kept private unless you
          will call them by your design... GoF's words do not 
          apply everywhere...


          Actually usually I try to avoid comparing Java and 
          cplusplus, since they have so many different respects.
          when we are talking about cplusplus, the comparison
          always introduces confusion in my mind... 

          But for your words, IMO, it is a serious problem of 
          Java language(of course, YMMV). For example, without
          virtual private method, it is difficult to simulate the 
          design-by-contract policy...

          And BTW, Template Method does not require you put your
          algorithms into private/protected regions, but is this 
          really what you want?




          ☆─────────────────────────────────────☆
             jasss (robot) 于  (Wed Aug  3 16:33:22 2005)  提到:




          But for cplusplus, access control and overriding are 
          totally independent/orthogonal concepts. As you know,
          access control specifies who can call the controlled 
          functions, however virtual functions *are* parts of 
          the interface by design, and the derived classes should 
          respect this fact while using cplusplus...




          ☆─────────────────────────────────────☆
             goer (玨) 于  (Wed Aug  3 16:42:39 2005)  提到:


          繼承來的方法應(yīng)該也算是這個(gè)類的方法吧?






          ☆─────────────────────────────────────☆
             jasss (robot) 于  (Wed Aug  3 16:47:24 2005)  提到:



          LOL, actually this issue had been discussing for a long time...

          Actually I know several opinions and its 
          supporters(not accurate enough, maybe) :

          1. This should be removed at the language level. 
                                         (Arnald)

          2. You can do it, but it is not very useful and 
             use it at your own risk.
                                         (Scott Mayer)

          3. This is useful, use it whenever it fits.
                                         (Bjarne Stroustrup)

          4. virtual function should be private by default.
             and make the interface non-virtual.
                                         (Herb Sutter)


          Actually this question is really a good question/topic,
          since the understanding for this issue will dominate 
          the design policy...




          ☆─────────────────────────────────────☆
             hlyu76 (魚啊魚) 于  (Wed Aug  3 18:49:20 2005)  提到:

          private virtual 表明這是一個(gè)內(nèi)部實(shí)現(xiàn),不允許子類或其他類調(diào)用(如果是protected的,無法保證子類不調(diào)用這個(gè)實(shí)現(xiàn))。
          但給了子類一個(gè)提供自己實(shí)現(xiàn)的途徑(這個(gè)實(shí)現(xiàn)無法調(diào)用父類的實(shí)現(xiàn))。







          ☆─────────────────────────────────────☆
             longda (longda) 于  (Wed Aug  3 23:05:08 2005)  提到:

          這個(gè)靜態(tài)綁定好像有問題啊,java里有靜態(tài)綁定的函數(shù)調(diào)用嗎?


          ☆─────────────────────────────────────☆
             ironcool (除了我還能是誰) 于  (Thu Aug  4 11:04:01 2005)  提到:

          我覺得就好像自己和自己做迷藏
          程序的行為,當(dāng)然是自己負(fù)責(zé)啊

          posted on 2005-08-07 23:26 weidagang2046 閱讀(2664) 評(píng)論(0)  編輯  收藏 所屬分類: C/C++

          主站蜘蛛池模板: 林州市| 方山县| 青田县| 昭苏县| 大竹县| 蒙阴县| 临海市| 邻水| 大渡口区| 黄山市| 封丘县| 恩平市| 和顺县| 太和县| 大荔县| 云安县| 三河市| 大化| 蓬安县| 惠东县| 滕州市| 星子县| 阳泉市| 榆社县| 南华县| 镇江市| 靖远县| 泰安市| 泗水县| 唐海县| 电白县| 东乌| 天等县| 恭城| 阳曲县| 罗平县| 临猗县| 凤城市| 垦利县| 浏阳市| 芦山县|