在使用TclOO继承类时,我偶然发现了变量作用域。 下面的成员变量nCrumbs对于继承的类是不可见的,而不重复声明。
有没有办法避免从超类复制所有变量声明?
(我阅读了所有的OO文档,特别是oo :: define和oo :: object,也是非导出的东西,用Google搜索。有很多概念可以解决各种问题,我迷路了。 我正在寻找能够使继承类尽可能简单的东西。但是,超类中可能包含任何花哨的复杂代码。)
非常感谢任何帮助,谢谢。
oo::class create toaster {
variable nCrumbs; #declaration
constructor {} {
set nCrumbs 0; #definition
}
method toast {nSlices} {
if {$nCrumbs > 50} {
error "== FIRE! FIRE! =="
}
set nCrumbs [expr $nCrumbs+4*$nSlices]
}
method clean {} {
set nCrumbs 0
}
}
oo::class create smartToaster {
superclass toaster; #inherit
variable nCrumbs; #<======= have to declare again
method toast {nSlices} {
if {$nCrumbs > 40} {
my clean
}
next $nSlices; #call superclass method
}
}
set clsToaster [smartToaster new]
$clsToaster toast 2
答案 0 :(得分:1)
该变量在对象实例的私有命名空间中物理定位(如果您可以为代码说明)。通过在声明中执行variable
,您将指示方法绑定仅在没有其他命令的情况下使其可用。
但是,是的,子类必须使用variable
来默认查看它,或者使用标准Tcl变量范围管理命令之一,例如upvar
或namespace upvar
,甚至是私人variable
方法。
oo::class create smartToaster {
superclass toaster
method toast {nSlices} {
my variable nCrumbs
if {$nCrumbs > 40} {
my clean
}
next $nSlices
}
}
oo::class create smartToaster {
superclass toaster
method toast {nSlices} {
namespace upvar [namespace current] nCrumbs nc
if {$nc > 40} {
my clean
}
next $nSlices
}
}
以前不是这样,但发现它太混乱了;类的变量声明只影响该类的方法,而不影响其子类。
[编辑]:可以通过适当的元类魔法使父母的变量在孩子身上也可见:
oo::class create Class {
superclass oo::class
constructor args {
next {*}$args
set cs [info class superclasses [self]]
while {[llength $cs]} {
set cs [concat [lassign $cs c] [info class superclasses $c]]
oo::define [self] variable -append {*}[info class variables $c]
}
}
}
证明这一点:
% Class create foo {
variable x
}
::foo
% Class create bar {
superclass foo
variable y
}
::bar
% Class create boo {
superclass bar
variable z
}
::boo
% info class variables boo
z y x
虽然我一般不推荐这个,因为它使子类在超类发展时更加脆弱,而且它不跟踪超类的任何更改,所以很容易设置一些脚本。您只需将智能委托给您自己的元类,并使用它来构建所有操作类(从那里开始纯粹是传统的TclOO类)。
答案 1 :(得分:0)
所以我假设默认情况下没有可用的机制使所有超类变量可用。
我目前的解决方案是收集所有变量名称,然后通过一次调用声明它们。 但是,我必须在每种方法中重复这一点。我想把declareSuperclassVars放在方法之外。 这有可能吗?也许用另一种方法?
由于
oo::class create toaster {
variable nCrumbs; #declaration
variable toTest; #another one nowhere defined
constructor {} {
set nCrumbs 0; #definition
}
method toast {nSlices} {
if {$nCrumbs > 50} {
error "== FIRE! FIRE! =="
}
set nCrumbs [expr $nCrumbs+4*$nSlices]
}
method clean {} {
set nCrumbs 0
}
method declareSuperclassVars {} {
my variable lSuperclassVars
set lSuperclassVars [info vars]; #fill variable list
uplevel 1 {
my variable lSuperclassVars
eval "my variable $lSuperclassVars"
}
}
}
oo::class create smartToaster {
superclass toaster; #inherit
#declareSuperclassVars; #<======= would like to do it here
method toast {nSlices} {
my declareSuperclassVars; #declare all at once
if {$nCrumbs > 40} {
my clean
}
next $nSlices; #call superclass method
}
}
set clsToaster [smartToaster new]
$clsToaster toast 2