具有Incr Tcl的类对象的分层结构

时间:2013-07-09 14:18:10

标签: class tcl incr-tcl itcl

我正在尝试实现类/子类对象的层次结构,例如:

|-- Class1                  # mainClass
|   |-- SubClassA           # subClass
|   `-- SubClassB           # subClass
`-- Class2                  # mainClass
    |-- SubClassA           # subClass
    `-- SubClassB           # subClass

这里的要点是能够在每个主要类中声明不同的子类同名(并使其变量独立)。

(注意:我在这里谈论的是在执行期间创建的类<​​strong>对象的层次结构,而不是关于不同类的遗产。)

对Tcl(命名空间,范​​围......)特有的一些高级方面相当不熟悉,我尝试了以下代码:

package require Itcl

itcl::class subClass {
  variable InternalVariable
  constructor {} {
    puts "($this)     Current namespace      : [namespace current]"
    puts "($this)     InternalVariable scope : [itcl::scope InternalVariable]"
  }
}

itcl::class mainClass {
  variable SubClassesList
  constructor {} {
    set SubClassesList {}
    puts "($this)     current namespace      : [namespace current]"
    puts "($this)     SubClassesList scope   : [itcl::scope SubClassesList]"
  }
  method newSubClass {argName} {
    lappend SubClassesList [subClass $argName]
    puts "($this)     SubClassesList         : {$SubClassesList}"
  }
}

# Create the two main classes
mainClass Class1
mainClass Class2

# Add some subclasses to Class1 and Class2
Class1 newSubClass SubClassA
Class1 newSubClass SubClassB
Class2 newSubClass SubClassC
Class2 newSubClass SubClassB

在创建SubClassB的第二次出现时产生错误:

(::Class1)     current namespace      : ::mainClass
(::Class1)     SubClassesList scope   : @itcl ::Class1 ::mainClass::SubClassesList
(::Class2)     current namespace      : ::mainClass
(::Class2)     SubClassesList scope   : @itcl ::Class2 ::mainClass::SubClassesList
(::mainClass::SubClassA)     Current namespace      : ::subClass
(::mainClass::SubClassA)     InternalVariable scope : @itcl ::mainClass::SubClassA ::subClass::InternalVariable
(::Class1)     SubClassesList         : {SubClassA}
(::mainClass::SubClassB)     Current namespace      : ::subClass
(::mainClass::SubClassB)     InternalVariable scope : @itcl ::mainClass::SubClassB ::subClass::InternalVariable
(::Class1)     SubClassesList         : {SubClassA SubClassB}
(::mainClass::SubClassC)     Current namespace      : ::subClass
(::mainClass::SubClassC)     InternalVariable scope : @itcl ::mainClass::SubClassC ::subClass::InternalVariable
(::Class2)     SubClassesList         : {SubClassC}
command "SubClassB" already exists in namespace "::mainClass"

我可能错过了关于类命名空间的观点,因为我不明白变量SubClassesList如何具有两个不同的范围,但是“相同”的命名空间/名称(来自调试输出)。

我尝试在newSubClass方法中创建一个新的命名空间,但它没有解决问题和/或添加一些不可分割的变量命名空间错误......

method newSubClass {argName} {
  set SubClassName "[namespace current]::[namespace tail $this]"
  puts "($this)     SubClassName           : $SubClassName"
  namespace eval $SubClassName "lappend SubClassesList [subClass $argName]"
  puts "($this)     SubClassesList         : {$SubClassesList}"
}

有没有想过要做这样的事情?

P-S:我使用[incr Tcl]在我的项目中实现类,以兼容现有环境,但如果有人认为其他OO实现会更好/更容易,请告诉我......


编辑:

使用namespace eval + namespace inscope在与subClass对象名称对应的新命名空间中创建mainClass个对象,找到解决方案:

itcl::class mainClass {
  variable SubClassesList
  constructor {} {
    set SubClassesList {}
    puts "($this)     current namespace      : [namespace current]"
    puts "($this)     SubClassesList scope   : [itcl::scope SubClassesList]"
    # Create a new namespace corresponding to class name
    namespace eval $this {}
  }
  method newSubClass {argName} {
    # Create the subClass object in the $this namespace
    lappend SubClassesList [namespace inscope $this subClass $argName]
    puts "($this)     SubClassesList         : {$SubClassesList}"
  }
}

1 个答案:

答案 0 :(得分:2)

我认为您在对象之间感到困惑:Class是用于创建对象的蓝图或模板。在您的示例中:

  • mainClasssubClass
  • Class1Class2SubClassASubClassBSubClassC是对象,类的AKA实例

在Itcl中,每个类都有自己的命名空间,例如,类mainClass拥有一个名为::mainClass的命名空间 - 您在输出中看到了这个证据:

(::Class1)     current namespace      : ::mainClass
^^^^^^^^^^

此外,每个对象都有自己的命名空间::::。例如,SubClassB对象拥有名称空间::mainClass:SubClass

(::mainClass::SubClassB)     InternalVariable scope : @itcl ::mainClass::SubClassB ::subClass::InternalVariable
^^^^^^^^^^^^^^^^^^^^^^^^

这意味着,你不能拥有两个共享相同名称的对象 - 这就是你得到的错误。如果您仍希望示例工作,请使用#auto作为对象名称:

method newSubClass {argName} {
    lappend SubClassesList [subClass #auto] ;# <=== Use automatic naming
    puts "($this)     SubClassesList         : {$SubClassesList}"
}