0

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

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

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

(注意:我在这里谈论的是在执行期间创建的类对象的层次结构,而不是不同类的继承。)

对 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}"
}

任何想法执行这样的事情?

PS:出于与现有环境的兼容性原因,我使用 [incr Tcl] 在我的项目中实现类,但如果有人认为其他 OO 实现会更好/更容易,请告诉我......


编辑 :

通过使用namespace eval+在与对象名称对应的新命名空间namespace inscope中创建对象找到了解决方案:subClassmainClass

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}"
  }
}
4

1 回答 1

2

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

  • mainClass并且subClass是类
  • Class1, Class2, SubClassA, SubClassB, 和SubClassC是对象,又名类的实例

在 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}"
}
于 2013-07-10T04:17:08.847 回答