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

の 2 回目のオカレンスを作成するときにエラーが発生します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"

変数が2つの異なるスコープを持つことができる方法を理解していない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クラスです
  • Class1Class2SubClassASubClassBおよびSubClassCはオブジェクトであり、別名クラスのインスタンスです

Itcl では、各クラスには独自の名前空間があります。たとえば、クラスmainClassは という名前の名前空間を所有しています::mainClass。この証拠は、コードの出力に示されています。

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

さらに、各オブジェクトには独自の名前空間 :::: があります。たとえば、SubClassBオブジェクトは名前空間を所有しています::mainClass:SubClass:

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

つまり、同じ名前を共有する 2 つのオブジェクトを持つことはできません。これがエラーです。それでも動作するように例を示したい場合は#auto、オブジェクト名に次を使用します。

method newSubClass {argName} {
    lappend SubClassesList [subClass #auto] ;# <=== Use automatic naming
    puts "($this)     SubClassesList         : {$SubClassesList}"
}
于 2013-07-10T04:17:08.847 に答える