Tcl OO中自定义重写new方法未被调用的原因排查
为何Tcl OO编程中new方法似乎无法被重写?
问题复现代码如下:
% oo::class create A { method new {} { puts "In A's new"; return [next] } } ::A % A new ::oo::Obj15 % A new ::oo::Obj16 % info class definition A new {} { puts "In A's new"; return [next] } % info class call A new {method new ::A method}
现象核心原因
出现这个问题的本质是Tcl OO中类定义体内直接声明的method属于实例方法,仅对类生成的实例对象生效,不会成为类对象自身的可调用方法,相关逻辑可以拆成三点理解:
- Tcl OO基于元对象模型实现,所有类本身也是对象:通过
oo::class create A创建的类A,本质是元类oo::class的实例。执行A new时,是把A作为普通对象调用new方法,方法查找会沿着A自身所属类(即oo::class)的继承链向上匹配,最终调用的是oo::class内置的new方法,完全不会查找A为自身实例准备的方法表。 - 类A定义块内直接写的
method new {} {...},是注册在A的实例方法表中的,只有A创建出来的实例对象调用new时才会触发。验证方式很简单:先执行set obj [A new]拿到实例,再执行$obj new,就能看到In A's new的打印逻辑正常触发。 - 通过
info class definition A new能查到该方法,是因为这个命令的设计作用就是查询指定类为实例提供的方法定义,能查到不代表类对象自身可以调用到这个方法。
正确重写类级new方法的方式
如果需要让A new调用时触发自定义逻辑,需要定义类自身的方法(即类方法),在方法声明前加self前缀即可:
oo::class create A { # 加self前缀后,该方法属于类A自身,A new时会优先触发 self method new {} { puts "In A's class-level new" return [next] } }
此时再执行A new,会先执行自定义打印逻辑,再通过next调用元类oo::class的原生new逻辑,完成实例创建和返回。
如果需要批量修改一批类的new创建行为,可以自定义元类,把自定义new逻辑写在元类中,所有指定该元类创建的类,调用new时都会统一走自定义逻辑。
内容的提问来源于stack exchange,提问作者Octowuss
相关产品推荐
相关产品推荐

