コメント: operator=()と継承

どうもご無沙汰です。ベンチプレスが挙がらなくなったホークスファンです。(わかるかな)
別件でググっていたところ奇跡的にたどり着いたのでふと読んでみました。

さて本題ですが、これはシンプルに B::operator=(B) が自動で生成されて、そのなかで A::operator=(A) が呼ばれているのではないかと思いました。
ま、勘違いだったらなかったことにしてください。

では仕事にもどるとします。

投稿者 soleus : April 11, 2008 03:18 PM

>soleusさん、改めTさん
お久しぶりです。お元気ですか? こちらの方は今年度に入ってからジムの年間パスを買う仲間が増えて嬉しい限りです。でもあの記録を打ち破れる人はでそうにないのでご安心ください(笑)
んで本題ですが、確かにそう考えると納得がいきますね。そうするとサブクラス内で自動生成されるoperatpor=は、サブクラス内で定義されたデータメンバのみのコピー、並びに親クラスのoperator=を呼び出している、と考えられますね。ありがとうございます。

投稿者 fenrir : April 12, 2008 10:37 AM

代入演算子のオーバーロードについて調べていて辿り着きました。
派生クラスでオーバーライドする場合、通常は基底クラスのメソッドはvirtualにすると思います。
記事のサンプルコードでは、基底クラスでvirtualになっておらず、別メソッドとして実装されているためそのような動作になっていると思います。
こちらで試したところ、基底クラスでvirtual指定すると、(4)のケースでoperator=(B)が呼ばれました。

以上、気になりましたのでコメントしました。

投稿者 通りすがり : February 24, 2009 12:22 PM

>通りすがりさん
コメントありがとうございます。『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についてです。よろしければテストされた環境を教えていただけないでしょうか。

投稿者 fenrir : February 25, 2009 09:05 AM

こちらにアップされているサンプルコードを見てみました。
そして分かったのは、class Aとclass Bで使用されているself_tの型がclass AではAでclass Bでは Bになっています。これだとコンパイル時に別メソッドと見なされるのでオーバーライドされないですね。
class Bでも戻り値をAにしてやるとオーバーライドされると思います。

投稿者 通りすがり : February 25, 2009 12:28 PM

>通りすがりさん
おっしゃるとおりだと思います、お手数おかけしています。
しかしここではB::operator=の戻り値の型はBであって欲しいという都合がありまして…。例えばsome_functionがclass Bのみで定義されていて、(b=b_another).some_function()、および(b=a).some_function()(注:こちらは内部的に明示アップキャストをすることによって処理)をする場合が考えられます。大人しくB::operator=(B)関数を定義しておけば解決するのですが、僕の感覚が少しずれているのか、気持ち悪いなぁ、というのがこの記事の内容でした。

投稿者 fenrir : February 25, 2009 03:21 PM

なるほど。
もともとオーバーライドしていたわけではなかったのですね。

もうお気付きのようですが、
上で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ではありません。

少々くどい説明になってしまい申し訳ありません(汗)

投稿者 通りすがり : February 26, 2009 12:58 AM
コメントする









名前、アドレスを登録しますか?
(次回以降コメント入力が楽になります)
  • 匿名でのコメントは受け付けておりません。
  • 名前(ハンドル名可)とメールアドレスは必ず入力してください。
  • メールアドレスを表示されたくないときはURLも必ず記入してください。
  • コメント欄でHTMLタグは使用できません。
  • コメント本文に日本語(全角文字)がある程度多く含まれている必要があります。
  • コメント欄内のURLと思われる文字列は自動的にリンクに変換されます。