动动手脚,protected不再被保护

今天看Delphi的e-book,看到在delphi中以一种违反访问权限规则的“欺骗”方式访问其父类。此时我想到一个问题,就是当protected对对象进行封装保护时,是有很明显的后门的。在C#中,我们很容易将protected暴露为public。例如:

 

class Base
    
{
        
protected void Print()
        
{
            Console.Write(
"This is protected method in Base Class!");
        }

    }


    
class Derived:Base
    
{
        
public new void Print()
        
{
            
base.Print();
        }

    }

通过这种方法,我们就可以在另外的类中毫无顾忌地访问Base的Print()方法了。

class OtherClass
    
{
        
        [STAThread]
        
static void Main(string[] args)
        
{
            Derived d 
= new Derived();
            d.Print();
            Console.ReadLine();
        }

    }

换句话说,如果我们想暴露某个类的受保护方法或字段,OK,我们只需要生成一个wrapper类(对使用者,就好比是包装了该类,实质上是采用继承的方法),派生这个类,然后new这个受保护方法,并将其定义为public就可以了。如此一种“欺骗”的方式,轻而易举就窃取了类的受保护方法。

也就是说,通过继承的方法,我们可以提升父类设置的访问级别。当然对于父类的private是无能为力的。

所以,对于派生类而言,是应该直接派生其受保护方法呢?还是应该new一个新的,需要我们根据实际情况来选择。

posted @ 2004-11-17 16:26 张逸 阅读(3540) 评论(21) 编辑 收藏

 回复 引用 查看   
#1楼 2004-11-17 16:33 umlchina      
呵呵,老兄
protected声明的方法本来就是为了让其子类可以使用
不让外部使用的方法你直接用private多简单


 回复 引用 查看   
#2楼[楼主] 2004-11-17 16:36 wayfarer      
呵呵。我已经意识到这点,其实我想说的是派生类可以提升其父类的访问级别。

所以我已经改了,没想到你回复得这么快,呵呵^_^


 回复 引用 查看   
#3楼[楼主] 2004-11-17 16:41 wayfarer      
还有一个问题是,这个父类并非你实现的。如果你需要将父类的某些方法暴露出来,那就需要这样动动手脚了。

因此你在设计类库时,为了保证重用的灵活性时,还是应多考虑使用protected,而不是private,即使你的目的是不想让外部调用。一旦声明为private,可就被封装死了,想改就只有该父类的代码了。可惜的是,你不是父类的设计者,你是无权更改父类的代码的。

因此,选择protected还是private,这个选择还是很重要的。


 回复 引用   
#4楼 2004-11-17 16:41 he
派生类可以提升其父类的访问级别
-----------------------
这话说的真晦涩

 回复 引用 查看   
#5楼[楼主] 2004-11-17 16:55 wayfarer      
public
^
internal
^
protected
^
private

这就是所谓的"提升访问级别"罗,呵呵:)

 回复 引用 查看   
#6楼 2004-11-17 17:01 lichdr      
這叫cracker class,這種技巧早就再用了。
主要是用在不同的程序單元的地方。

兩個類在同一個單元就不用這麼累的。

 回复 引用   
#7楼 2004-11-17 17:25 Ninputer[未注册用户]
internal是没法和protected比较的,如果非要比较,那么我认为internal无法穿透程序集的边界,所以internal不如protected。

public > protected internal > protected > internal > private

 回复 引用 查看   
#8楼[楼主] 2004-11-17 17:42 wayfarer      
在.Net Framework,确实提供了五种访问级别。不过我觉得Ninputer写的顺序似乎有误,应该是:
public > protected > internal > protected internal> private。
但是在C#中,只提供了四种,不包括protected internal。

不过对于internal和protected,没有完全的访问级别的高低界限。因为对于internal而言,只要是在同一程序集中,即使不是该类的派生类,也可以访问。而对于protected来说,另外一个程序集的类也可以访问它,但前提是必须继承该类。

所以,internal和protected两者的访问级别,以集合的概念来看,似乎是两个相交的集合。而其交集就是protected internal修饰符。它只能被同一程序集的派生类访问。

 回复 引用   
#9楼 2004-11-17 17:54 Ninputer[未注册用户]
不,protected internal是protected的范围 加上 internal的范围,是并集不是交集。

你好像没有用过的样子,回去试试。C#当然支持它了。VB也支持,叫Protected Friend

 回复 引用   
#10楼 2004-11-17 21:12 Magicloud
记得设计模式中曾提到,少用继承,多用引用,即使在对象关系上是继承的。
 回复 引用   
#11楼 2004-11-17 22:32 Meyer
internal与protected 不好比较
但protected internal 确实比他门两个的范围大,这个可以比较

 回复 引用   
#12楼 2004-11-18 03:20 sumtec
敬请留意我的一篇新Blog,将对这一问题做出我个人的回答。今天太晚了,不放出来了,明天中午吧。
 回复 引用 查看   
#13楼[楼主] 2004-11-18 09:34 wayfarer      
声明的可访问性 意义
public 访问不受限制。
protected 访问仅限于包含类或从包含类派生的类型。
internal 访问仅限于当前程序集。
protected internal 访问仅限于从包含类派生的当前程序集或类型。
private 访问仅限于包含类型。

以上是MSDN对这几种访问限制的说明。Ninputer的观点是正确的,我将“当前程序集或类型”看作是“当前程序集的类型”了。protected internal 应该是internal和protected的并集,是我失误了。

不过我记得Applied .Net Framework里似乎还介绍了一种访问限制,是protected和internal的交集。这个修饰符在C#里并没有提供,但在IL里是有的,不知道是否正确,手边没有这本书,无法查阅了。

 回复 引用   
#14楼 2005-09-21 10:12 waj[未注册用户]
protected internal 应该是internal和protected的并集
 回复 引用   
#15楼 2006-02-15 16:48 老鼠甲[未注册用户]
考虑一个成员的访问域(Accessibility domains),应该同时考虑包含这个成员的类的访问域,一个成员实际的访问域是两者的交集
 回复 引用   
#16楼 2006-02-15 22:22 Ivony...[未注册用户]
C#不支持internal protected???

事实上protected更大的作用是避免我们敲一个"."后出现一大堆我们根本就不想看到的东西。

 回复 引用   
#17楼 2006-02-15 22:25 Ivony...[未注册用户]
wayfarer 还……

internal protected是internal和protected的交集。
不要老是咬文嚼字,自己试一下就全明白了。

尤其是VS2005的中文帮助,翻译错误多如牛毛……

 回复 引用   
#18楼 2006-05-29 14:03 静静地坐着[未注册用户]
并集!

FamilyOrAssembly -> protected internal
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=193386&SiteID=1

 回复 引用   
#19楼 2006-07-12 17:39 sirius[未注册用户]
public > protected internal > protected > internal > private
这个顺序应该是对的

protected:只能被自身和继承的子类来访问
internal:只能被程序集内部访问,如果子类不和父类在一个程序集的话,那么子类是没有办法访问的。
protected internal:是两个的并集,无论是不是在一个程序集,子类都能访问,而且自己所在的程序集内的都能访问,说得有点乱,不过,我是理解了
^_^

 回复 引用   
#20楼 2006-07-12 17:40 sirius[未注册用户]
不过,protected和internal,应该不能简单的说谁的范围大,谁的范围小的
如果都在同一个程序集那么,自然是internal的范围大
如果子类和父类不在一个程序集的话,可能就另说了吧?应该