类方法中的“超级”关键字

时间:2012-06-03 20:36:43

标签: inheritance smalltalk class-method

我正在学习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 BB对象之间有什么区别?我开始认为B对象是类static的一个特殊的单一实例(就像B属性在其他语言中实现一样),但仍然 - 我已经检查过了它的类是B,子类是A

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

5 个答案:

答案 0 :(得分:4)

selfsuper始终引用同一个对象,即当前接收者。唯一的区别是self开始在接收器的类中查找以下方法send,并在定义方法的超类中查找super

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

答案 1 :(得分:4)

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

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

答案 2 :(得分:3)

无论是在类还是对象中,

self和super都是一样的,因为类一个对象......

#createNew1& #createNew2是等价的。正如Lukas所解释的那样,超级仅仅意味着“在我的超类而不是我的班级中开始查找方法”。由于你没有在A或B中定义#new,你将查找超类,最终找到行为>> #new是否从A或B开始。#new首先调用#basicNew,它创建了返回B的新实例(即“a B”)。

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

答案 3 :(得分:2)

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

事实证明我在Smalltalk中误解了继承的基础以及如何调用方法。

我在想这样的代码......

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

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

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

但事实并非如此。

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

因此,调用^self new^super new,而不是在任何classess中定义new,会产生相同的效果 - 因为它们最终都会调用行为的 newself

的上下文中实现

答案 4 :(得分:0)

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

A class>>new
    ^A basicNew