weidagang2046的专栏

物格而后知致
随笔 - 8, 文章 - 409, 评论 - 101, 引用 - 0
数据加载中……

C++容许private方法是virtual是不是一个漏洞

发信人: eastcrusader (昨我已逝), 信区: CPlusPlus
标  题: [合集] C++容许private方法是virtual是不是一个漏洞
发信站: 水木社区 (Fri Aug  5 09:36:12 2005), 站内

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

如下面的代码,输出是
Base::doPublic
Derived::doPrivate
这样岂不是可以让让一个子类冒充父类的private成员函数,不过好像一般private不会也没有必要声明为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)  提到:

这个不存在什么漏洞,也没有冒充的问题。C++中,除了构造函数内包含的虚函数调用是
早绑定(其他还有没有特殊情况一时记不起来),其他的虚函数调用都是晚绑定,也就是说,你在Derived 类中调用的时候,实际(this)也是函数调用的一个参数,和this指针有关的
vtable中也包含了private和protect部分的虚函数指针,vtable中的指针指向谁就是谁,责任明确,分工清楚,那来得冒充问题呢?




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

我觉得还是一个漏洞,这么说吧
有一个父类Account,有一个public方法doTransaction,有一个virtual private方法transfer(int money),doTransaction里面调用了transfer(1000),transfer的工作就是转帐1000块钱。
我要是有一个子类MyAccount,也定义了一个virtual private transfer(int money),但是转帐额度是moneyX2
Account *a = new MyAccount();
a->doTransaction();
组后调用的是子类MyAccount的transfer,这样就转了2000块钱,而不是本来的1000块钱,发了:)

java可能意识到这个问题,所以private方法,默认是final的,也就是private方法就是静态绑定的。








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

要出错也是用的人出错。。这不是纯属活该嘛。。




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


如果doTransaction()本身就是virtual function,派生类直接override它转2000块钱,
你是否也认为是漏洞?





☆─────────────────────────────────────☆
   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转帐两倍,checkUserBalance时查的是1000,实际转了2000。










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


如果doTransaction本身就是virtual function呢?我在派生类中直接把if给去掉。
你是否认为virtual function都是漏洞?



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


:我觉得还是一个漏洞,这么说吧
:有一个父类Account,有一个public方法doTransaction,有一个virtual private方法
:transfer(int money),doTransaction里面调用了transfer(1000),transfer的工作就是
:转帐1000块钱。
:我要是有一个子类MyAccount,也定义了一个virtual private transfer(int money),但
:是转帐额度是moneyX2
:Account *a = new MyAccount();
:a->doTransaction();
:组后调用的是子类MyAccount的transfer,这样就转了2000块钱,而不是本来的1000块钱,
:发了:)
:

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,没有办法获得这个token,getSessionToken返回一个类似令牌的东东验证身份,每次操作transfer必须带上这个token。









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





如果要实现template pattern,可以把希望子类重载的成员声明成protected啊
Java禁止private作为virtual,一样也可以实现template pattern





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


你没有理解我的意思。子类和父类要保持IS-A关系,子类必须满足父类的所有invariants。
然而,overridding机制本身不能保证这一点。override掉父类的任何一个方法,都有可能
破坏invariant。所以你看,这不是private或者public的问题,这是virtual的固有问题。

就你那个例子,我的doTransaction()为什么要调用transfer()? 我可以做任何事,我
甚至可以delete this。

你需要的,是能表达invariant/constraint的语言。禁止virtual private不会带来什么。



☆─────────────────────────────────────☆
   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)  提到:

的确没有理解你的意思
这么说吧,一个private的方法,按说只能够被自己这个类的方法调用
现在private方法可以是virtual的,也就导致有的情况下,private方法可以被不是这个类的方法调用
这样,不和private的初衷矛盾吗







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


Base::private_method()自然只能被Base的方法调用。



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

我的Derived方法里的private方法,却被Base的public方法调用了






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

总觉得这个讨论比较没有意义。干嘛要把你不想被子类改的声明为virtual,还有private方法就是子类不能调用啊,变成了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对private方法能不能够是virtual上有差异
java比C++出现的晚,有意的不容许private是virtual肯定是java语言的发起者觉得C++这个特性不适合java

如果程序员有意识的不个private方法弄成virtual的,两者没有区别
就此结贴,不再讨论






☆─────────────────────────────────────☆
   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本来就是子类的指针,当然调用子类的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)  提到:


继承来的方法应该也算是这个类的方法吧?






☆─────────────────────────────────────☆
   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 表明这是一个内部实现,不允许子类或其他类调用(如果是protected的,无法保证子类不调用这个实现)。
但给了子类一个提供自己实现的途径(这个实现无法调用父类的实现)。







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

这个静态绑定好像有问题啊,java里有静态绑定的函数调用吗?


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

我觉得就好像自己和自己做迷藏
程序的行为,当然是自己负责啊

posted on 2005-08-07 23:26 weidagang2046 阅读(2629) 评论(0)  编辑  收藏 所属分类: C/C++


只有注册用户登录后才能发表评论。


网站导航: