どうもご無沙汰です。ベンチプレスが挙がらなくなったホークスファンです。(わかるかな)
別件でググっていたところ奇跡的にたどり着いたのでふと読んでみました。
さて本題ですが、これはシンプルに B::operator=(B) が自動で生成されて、そのなかで A::operator=(A) が呼ばれているのではないかと思いました。
ま、勘違いだったらなかったことにしてください。
では仕事にもどるとします。
>soleusさん、改めTさん
お久しぶりです。お元気ですか? こちらの方は今年度に入ってからジムの年間パスを買う仲間が増えて嬉しい限りです。でもあの記録を打ち破れる人はでそうにないのでご安心ください(笑)
んで本題ですが、確かにそう考えると納得がいきますね。そうするとサブクラス内で自動生成されるoperatpor=は、サブクラス内で定義されたデータメンバのみのコピー、並びに親クラスのoperator=を呼び出している、と考えられますね。ありがとうございます。
代入演算子のオーバーロードについて調べていて辿り着きました。
派生クラスでオーバーライドする場合、通常は基底クラスのメソッドはvirtualにすると思います。
記事のサンプルコードでは、基底クラスでvirtualになっておらず、別メソッドとして実装されているためそのような動作になっていると思います。
こちらで試したところ、基底クラスでvirtual指定すると、(4)のケースでoperator=(B)が呼ばれました。
以上、気になりましたのでコメントしました。
>通りすがりさん
コメントありがとうございます。『virtualがない』ということで、なるほど、と思いこちらても追試をしてみました。しかしながら結果は変わらず、(4)のケースでもA::operator=(A)が呼ばれてしまいました(なおダウンロードできるコードに倣ってself_tについてはclass Aでtypedef A self_t;、class Bではtypedef B self_t;としています)。試した環境はVisual Studio Express Edition 2008とgcc 3.4.4についてです。よろしければテストされた環境を教えていただけないでしょうか。
こちらにアップされているサンプルコードを見てみました。
そして分かったのは、class Aとclass Bで使用されているself_tの型がclass AではAでclass Bでは Bになっています。これだとコンパイル時に別メソッドと見なされるのでオーバーライドされないですね。
class Bでも戻り値をAにしてやるとオーバーライドされると思います。
>通りすがりさん
おっしゃるとおりだと思います、お手数おかけしています。
しかしここではB::operator=の戻り値の型はBであって欲しいという都合がありまして…。例えばsome_functionがclass Bのみで定義されていて、(b=b_another).some_function()、および(b=a).some_function()(注:こちらは内部的に明示アップキャストをすることによって処理)をする場合が考えられます。大人しくB::operator=(B)関数を定義しておけば解決するのですが、僕の感覚が少しずれているのか、気持ち悪いなぁ、というのがこの記事の内容でした。
なるほど。
もともとオーバーライドしていたわけではなかったのですね。
もうお気付きのようですが、
上でsoleusさんが言われているように
デフォルトではA::operator=(A)とB::operator=(B)が作られます。
そしてb = bをした場合、A::operator=(A)とB::operator=(B)の両方が呼ばれます。
これは、「A::operator=(A)だけが呼ばれているわけではない」
ということです。
※A::operator=(A)が呼ばれないと、Aのメンバは代入されませんよね?B::operator=(B)ではBのメンバのみ代入されます。
サンプルコードでは、たまたまA::operator=(A)のみオーバーロードしていたため、こちらに気付いただけで、fenrirさんの感覚が特にずれているわけではありません。B::operator=(B)もちゃんと呼ばれています^^
b = bでaの参照が最終的に帰るわけではないので、(b = b)としてもちゃんとclass Bのメソッドは使えるはずです。
ちなみにB::operator=(A)は自動で作られないので、自分で定義しない限り呼ばれません。
※未定義の状態でb = aをするとコンパイルが通りません。BはAですが、AはBではありません。
少々くどい説明になってしまい申し訳ありません(汗)