2014年5月28日水曜日

とりあえずBoost.Pythonを使う(5) return_internal_referenceで==をしてみると…

Boost.Pythonで保有しているオブジェクトをgetterなどで返すときはreturn_internal_referenceを指定すると便利だ。
class_<Surface>("Surface", init<>())
        .def("__str__", &Surface::toString)
        .add_property("shape", 
                      make_function(&surface_get_shape, return_internal_reference<>()),
                      make_function(&surface_set_shape, with_custodian_and_ward_postcall<1, 2>())
                      )

こうするとオブジェクトを取り出して値を変更すると内部の値も変わっている。
唐突だが、以下の例では途中で片方の値だけ変更したけど、もう片方も変わっている。
shape = eva.Sphere(13,2)
self.surf.shape = shape

a = self.surf.shape
b = self.surf.shape
print(a,b)

a.r = 1000
print(a,b)

出力結果:
Sphere r: 13, erad: 2 Sphere r: 13, erad: 2
Sphere r: 1000, erad: 2 Sphere r: 1000, erad: 2

これは想定内の働き。でもここで
a == b
とすると、Falseになってしまう。なぜだ。
中身をみるとどうやらアドレスが別らしい。BoostPython側で何か処理をしてくれていてこうなったのだろう。


こうなるとオブジェクトが等しいという判断は、オブジェクトのアドレスでなく、中身の値で判断させるようにしたほうが良さそうだ。

そこで必ず==を実装するようにすべく、
C++のVirutualクラスに==や!=をオーバーライドさせるように書く。
引数がネックになってどう書いていいかわからなかった。
書き方を調べると以下のような記事が見つかった。
https://groups.google.com/forum/#!topic/comp.lang.c++.moderated/VAm49RqRico


メモがてら抜粋させていただくと
bool Derived::operator==(const Base &rhs) const
{
    const Derived *pRhs = dynamic_cast<const Derived *>(&rhs);
    if (pRhs == NULL) { // rhs is of another type derived from Base
         return false;
     } else {
          // Do work to compare two Derived objects
     }
}
違うクラスが来るとfalseになるような仕様になっている。
コンパイルも通ったし、めでたしめでたし。

ただ、質問の解答は下に続いていて、
そもそもPure Virtualクラスに==をオーバライドさせるとか設計が悪すぎるとか書いてある。んーどうすれば一番良いのだろうか…





0 件のコメント:

コメントを投稿