如何修改::oo::interface类使Tcl 8.5中::oo::objdefine正常工作?
问题
在Tcl 8.5 + TclOO 1.0.x环境中实现接口类及对象序列化功能时,调用::oo::objdefine $abc class ::ABC报错:"may not change a non-class object into a class object"。通过GDB调试发现调用该命令时oPtr->classPtr为NULL,复现代码如下:
package require Tcl 8.5 package require TclOO # 序列化类 ::oo::class create ::oo::serializable {} # 接口元类实现 ::oo::class create ::oo::interface { superclass ::oo::class mixin ::oo::InterfaceMixin self method create {name args} { set instance [next $name {*}$args] # 该行是问题根源 ::oo::define $instance superclass -append [self] return $instance } } namespace eval ::csh::oo {} # 带命名空间的类元类 ::oo::class create ::csh::oo::nclass { superclass ::oo::class mixin ::oo::InterfaceMixin ... } # 创建接口 ::oo::interface create ::SpecialMethods { } # 创建普通类,继承序列化类和接口 ::csh::oo::nclass create ::ABC { superclass ::oo::serializable ::SpecialMethods } # 创建序列化类实例 set abc [::oo::serializable new] # 在Tcl 8.5 + TclOO 1.0.x报错,Tcl 8.6.12正常 ::oo::objdefine $abc class ::ABC
解决方案
问题根源
原::oo::interface的create方法错误地将**元类::oo::interface**作为接口类的父类添加。::oo::interface是继承自::oo::class的元类,用它创建的接口类本身已是该元类的实例,无需再将其作为父类。这一错误导致接口类的父链中包含类类型对象,当普通类::ABC继承该接口后,其类层次结构不符合Tcl 8.5中TclOO对普通实例类的约束,最终触发类型检查错误。
修改后的::oo::interface实现
移除错误的父类追加操作即可解决问题:
::oo::class create ::oo::interface { superclass ::oo::class mixin ::oo::InterfaceMixin self method create {name args} { set instance [next $name {*}$args] # 移除错误的父类追加逻辑 return $instance } }
说明
修改后,接口类的父链不再包含类类型对象,::ABC继承接口类后可正常作为普通实例的类使用,调用::oo::objdefine $abc class ::ABC时不会再触发类型错误。
内容的提问来源于stack exchange,提问作者Christopher Horler
相关产品推荐
相关产品推荐

