有一种具有基于对象的访问级别的编程语言吗?

7
关于Java、C#、C++和PHP中访问级别的一个常见误解是,它适用于对象而不是类。也就是说,例如,类X的对象不能看到另一个X的私有成员。实际上,访问级别是基于类的,一个X对象可以轻松地引用另一个X的私有成员。
是否存在一种语言具有基于对象的访问级别?它们是替代还是附加于基于类的访问级别?这个特性对程序设计有什么影响?

我冒昧地将PHP添加到实现基于类的访问级别语言列表中。 - Ionuț G. Stan
3个回答

6
Ruby具有基于对象的访问级别。以下是《Programming Ruby》中的引用:
“protected”和“private”的区别相当微妙,并且在Ruby中与大多数常见的面向对象语言不同。如果一个方法是受保护的,它可以被定义类或其子类的任何实例调用。如果一个方法是私有的,它只能在调用对象的上下文中调用——即使调用者和该对象属于同一类,也无法直接访问另一个对象的私有方法。
以下是源代码:http://whytheluckystiff.net/ruby/pickaxe/html/tut_classes.html#S4 Java和Ruby之间的示例差异如下:
public class Main {
    public static void main(String[] args) {
        Main.A a1 = new A();
        Main.A a2 = new A();

        System.out.println(a1.foo(a2));
    }

    static class A
    {
        public String foo(A other_a)
        {
            return other_a.bar();
        }

        private String bar()
        {
            return "bar is private";
        }
    }
}

// Outputs
// "bar is private"

Ruby

class A
  def foo other_a
    other_a.bar
  end

  private
  def bar
    "bar is private"
  end
end

a1 = A.new
a2 = A.new

puts a1.foo(a2)

# outputs something like
# in `foo': private method `bar' called for #<A:0x2ce9f44> (NoMethodError)

在这个意义上,“私有”的表现更加真正的模块化。我希望其他语言也能采用类似的功能。 - Imagist
  1. 这在Java中是相同的。
  2. 我敢打赌这里的“never”意味着“除非你使用一些可以绕过这个限制的内部API,否则永远不会发生”。
- Aaron Digulla
@Aaron,我可能理解错了,但在Java中并不一样。我会发一个比较的例子。 - Ionuț G. Stan
Ionut,你能谈谈Ruby的这个特性如何改变程序设计吗?我很高兴知道有一种主流语言具备这个特性,但我最好奇的是这种语言选择对我们编写软件的影响。 - Carl Manaster
1
@Carl,老实说,我在Ruby方面没有太多经验,所以我无法给出很好的见解。我唯一能想到的是,这个特性允许更精细地控制副作用的来源。一个对象的内部结构不会受到另一个对象的影响,即使它们是同一类的实例,这是一件好事。但我不知道这个特性支持任何成语或模式。 - Ionuț G. Stan
这是给出的最佳答案,所以我接受了它,尽管我仍然非常好奇对程序设计的影响,希望有人能回答这个问题的那部分。 - Carl Manaster

0

没有一种语言在语义层面上支持这一点的主要原因是各种需求太不同了,很难找到一个足够大的共同点来支持这样的特性。数据隐藏本身已经够糟糕了,当你需要更精细的控制时,情况只会变得更糟。

这样的语言有优势,例如,您可以将某些数据标记为私有,除了创建它的对象之外,任何人都无法访问(密码就是一个很好的例子:即使在同一应用程序中运行的代码也无法读取它们)。

不幸的是,这种“保护”只是表面的,因为在汇编级别上,保护并不存在。为了高效,硬件需要支持它。在这种情况下,可能是在 RAM 中的单个字节级别上。这将使这样的应用程序非常安全,但速度极慢。

在现实世界中,您会在主板上的 TPM 芯片 中找到它,在 CPU 的 MMU 表中以非常粗略的形式出现。但这是在 4K 页面级别上,而不是在字节级别上。虽然有处理两者的库,但在我看来这并不算“语言支持”。

Java 有类似于 Security API 的东西。你必须用守卫来包装相关代码,询问当前的 SecuityManager 是否允许访问。
在 Python 中,你可以通过装饰器(针对方法和函数)或通过实现 __setattr____getattr__ 来实现类似的功能以进行字段访问。

3
你的分析在某种程度上是正确的,但是你似乎混淆了“数据封装”和“数据安全”。面向对象编程语言中的public、protected和private修饰符并不是用来“保护”数据的,而是将数据封装在类中,并且通过“保护”它们免受其他类的更改。这些修饰符并非在信息安全意义上用于“保护”数据。 - mipadi
如果不是出于安全考虑,这样的功能有何意义?对于数据封装,“private”已经足够了,因为您始终可以将单个字段包装在类中,以防止其他同一类的实例访问它。 - Aaron Digulla

-1
你可以在C#中实现这个功能,通过编写一个能够遍历堆栈并检查调用者所在对象的方法,如果不是当前类,则抛出异常。我不知道为什么你要这样做,但是我想提一下。

澄清:这件事应该在编译时完成。在运行时是无用的。 - EFraim
不,这是一种曲解。会产生可怕的运行时开销,并使用绝对不正确的方法。 - EFraim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接