Tcl: установка закрытой переменной принадлежащего экземпляра в классе - PullRequest
0 голосов
/ 04 февраля 2010

Допустим, следующие объявления кода:

itcl::class ObjectA {
    private variable m_ownedObject
    private variable m_someVariable

   constructor {} \
   {
        set m_ownedObject [ObjectA #auto]
   }

   protected method SetSomeVariable {newVal} {
       set m_someVariable $newVal
   }

   public method SomeMethod{} {
       $m_ownedObject SetSomeVariable 5
   }
}

Это единственный способ, которым я знаю, как изменить m_someVariable из SomeMethod в m_ownedObject. В других языках (скажем, C / C ++ / C # / Java, чтобы назвать несколько), я почти уверен, что мог бы просто сказать что-то вроде:

m_ownedObject.m_someVariable = 5

Есть ли способ сделать что-то подобное в tcl, или мне всегда нужно создавать защищенные методы получения и установки? Надеюсь, это достаточно ясно.

Ответы [ 3 ]

2 голосов
/ 07 июня 2011
$m_ownedObject configure -m_someVariable 5
1 голос
/ 04 февраля 2010

Вы не можете напрямую делать то, что просите в itcl. Однако, поскольку это Tcl, вы можете обойти это и напрямую установить переменную-член из в любом месте . Я использую вспомогательную подпрограмму с именем memv, которой вы передаете экземпляр и имя переменной, и она возвращает «ссылку» на эту переменную.

Очевидно, что это обходит закрытые / защищенные механизмы, которые создал Itcl, поэтому вы нарушаете абстракции, используя их. Это ваш звонок, хотите ли вы его использовать. Я считаю это бесценным для отладки, но не в производственном коде.

Пример использования:

set [memv m_ownedObject m_someVariable] 5

Код для memv:

proc memv {obj varname} {
  # have to look up the variable, which might be in a base class
  # so do 'info variable' to get that, and the full name is the 3rd element

  # next two lines handle pulling apart an array
  set aindex ""
  regexp -- {^(.+)\((.+)\)$} $varname ignore varname aindex

  set var [lindex [$obj info variable $varname] 2]

  if {$aindex == ""} {
    return [list @itcl $obj $var]
  } else {
    return [list @itcl $obj $var\($aindex\)]
  }
}

Аналогично, у меня есть вспомогательная подпрограмма с именем memv, которая позволяет вам вызывать любой метод (включая закрытые и защищенные методы). Его использование похоже

[memf m_ownedObject SetSomeVariable] 5

И это код:

proc memf {obj fcnname} {
  set f [$obj info function $fcnname]
  if {[llength $f] != 5} {
    error "expected '$obj info function $fcnname' to return something like 'private proc ::namespace::name args {...}' but got: $f"
  }
  set fullname [lindex [$obj info function $fcnname] 2]
  set namespace [namespace qualifiers $fullname]
  set function [namespace tail $fullname]
  return [itcl::code -namespace $namespace $obj $function]
}
1 голос
/ 04 февраля 2010

Если вы объявляете переменную как закрытую, это означает, что доступ к ней возможен только из класса. И это также верно для C / C ++ / Java ... поэтому я не уверен, что вы ожидаете.

В любом случае Tcl - динамический язык, поэтому вы можете сделать что-то подобное.

  itcl::class tclass {
      foreach v {time distance} {
        method get$v {} [subst -nocommands { return [subst $$v] }]
        method set$v nuval [subst -nocommands { set $v \$nuval } ]
        protected variable $v "Var $v"
      }
  }

И он создаст все getters и setters, что вам нужно;)

Вы можете найти больше информации здесь: http://wiki.tcl.tk/17667

...