具有继承/超类的TclOO变量范围

时间:2014-07-25 14:07:54

标签: tcl scope superclass

在使用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

2 个答案:

答案 0 :(得分:1)

该变量在对象实例的私有命名空间中物理定位(如果您可以为代码说明)。通过在声明中执行variable,您将指示方法绑定仅在没有其他命令的情况下使其可用。

但是,是的,子类必须使用variable来默认查看它,或者使用标准Tcl变量范围管理命令之一,例如upvarnamespace 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