6

我正在学习 Smalltalk 的基础知识。有一个super关键字用于从子类方法中的超类调用方法:

Object subclass: # A
   test
      ^1

A subclass: # B
   test
      ^2
   callSuper
      ^super test

所以B new callSuper评估为1

好的。这很清楚。

所以现在,我为类定义了一堆类方法B

createNew1
    ^super new
createNew2
    ^self new
create
    ^self
createSuper
    ^super

它们分别评估为a Ba BB一个错误(这向我表明这super不是对子类的强制转换,而是一种消息调度程序)。

B尽管有super关键字,为什么我会得到类的实例?a B和对象有什么区别B?我开始认为该B对象是 class 的一个特殊的单例实例(就像static在其他语言中实现的属性一样)B,但是 - 我已经检查过了,它的 class 是 aB并且 subclass 是 an A

super类方法中关键字的语义是什么?它与对象方法内部的语义有何不同?self调用内部类方法可以获得的对象到底是什么?

4

5 回答 5

4

self并且super总是引用同一个对象,即当前的接收者。唯一的区别是在接收者的类和定义该方法的超类中self开始查找以下方法发送。super

有关详细信息,请参见Pharo by Example的第 5 章。

于 2012-06-03T22:09:22.580 回答
4

你对第一个例子的回答是错误的。B new callSuper返回 1. Lukas 给出了 super 语义的准确定义。它基本上是“self”的别名,它修改了发送给它的消息的方法查找。self message将开始在接收者的类中查找方法,super message将开始在定义包含super message表达式的方法的类的超类中搜索(因此在这种情况下接收者的类不相关)。

在您的第二个示例中super newself new最终调用相同的方法(在行为层次结构中的某处定义),因为在这两种情况下这是最接近的方法定义。但是,如果您将 createNew 方法重命名为 new,那么new ^self new将是一个无限循环,而new ^super new调用 Behavior 方法。

于 2012-06-03T23:44:00.650 回答
3

self 和 super 在类或对象中的含义相同,因为类对象...

#createNew1 & #createNew2 是等价的。正如 Lukas 解释的那样,super 仅仅意味着“在我的超类而不是我的类中开始方法查找”。由于您没有在 A 或 B 中定义 #new,因此您将查找超类,最终找到 Behavior>>#new,无论您是从 A 还是 B 开始。#new 从调用 #basicNew 开始,它创建并返回B 的一个新实例(即“a B”)。

在#create & #createSuper 中,由于您没有查找任何内容,因此 self 和 super 再次等价,意思是“返回当前对象”(您指的是后者的错误是什么?)。现在这部分令人困惑。由于 Smalltalk 中的一切都是对象,因此这包括类本身。所以在这个上下文中,“当前对象”是 B,它是元类“B 类”的唯一实例。如果你真的有兴趣理解,我会一遍又一遍地阅读Pharo By Example的第 13 章,直到它有意义为止(我还没有达到这一点,哈哈)。

于 2012-06-04T03:10:15.443 回答
2

尽管所有其他答案在技术上都是正确的,但我将自己回答这个问题。那是因为我知道元类,而且似乎我脑子里有一个正确的语义super,但我仍然得到了意想不到的结果。

原来我误解了Smalltalk 中的继承基础以及方法的调用方式。

我在想,对于这样的代码......

Object subclass: #A
    test
        ^'A'
    getTest
        ^self test

A subclass: # B
    test
        ^'B'
    runTest
        ^super getTest

...表达式B new runTest被评估为'A'- 这意味着,来自超类的方法在向上转换的对象中进行评估。

但事实并非如此。

它被评估为'B',因为没有向上转换,并且当我们在超类方法中调用任何方法时 - 搜索从对象的真实类开始,而不是评估方法来自的类。

结果,调用^self newand ^super new,虽然没有new在任何类中定义 a ,但具有相同的效果 - 因为它们最终都在 的上下文中调用Behaviour 的 new实现self

于 2012-06-04T08:15:28.047 回答
0

是的,我想你现在明白了......
当你从 B 类发送 ^super new 时,你仍然向 B 类发送消息,只是消息是(超级新的)......
所以你创建了一个 B 的实例,
除非当然,如果您要定义

A class>>new
    ^A basicNew
于 2012-06-04T21:21:17.493 回答