3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

has-a継承が便利な場合、あるいはprotected継承は必要

Last updated at Posted at 2013-09-18

JavaというかAndroidとかでListenerを使うような場合、C++ではhas-a継承が使える。

まず、一々記述するのが面倒なのでlistenされる側をlisteneeと呼ぶことにする。

listenerを使うのは(listen)erが(listen)eeから何かイベントを受け取りたい場合だ。ここで、イベントを通知するメソッドをeeに純粋仮想関数として定義して、これをerが継承する。erでは通知メソッドを実装しなければならないし、当然イベントがあればerの通知メソッドが呼ばれる。

Listenerはeeからerの何かを呼ぼうとするとeeがerの実装に依存してしまうという逆依存問題を解消する方法でもあるが、この方法でもeeはerに依存していない。listenerの登録だのがクラスの構造に固定化されているのでlistenerの煩雑さもない。

これがhas-a継承が便利な場合。Javaだと多重継承が許されていないので汎用性を考えるとListenerなインターフェイスをimplementして使う方が向いているが、C++は多重継承できるのでただクラスを継承してハンドラを書くだけでいい(思うにJavaの方がいろいろ言われているC++より失敗言語っぽい。デストラクタがないからメモリ解放以外の後始末をまったく自動化できないし。例えばRAIIみたいにロックの解除とか)。

しかし、ここで普通にpublic継承してしまうとerはeeの一種扱いになってしまう。これは間違った関係なのでprivate継承かprotected継承にしてis-a関係を消す。ここでさらにer自体が抽象クラスでその子クラスの通知メソッドを置きたい場合もあるが、そんな場合はprotected継承で素直に実装できる。

これは **要らない子扱いされているprotected継承が必要になる稀有な例** だな。

まだ試してないけどな(ぉぃ

てかもっと単純に「has-a継承が便利な場合」

コールバックがある場合、代わりに仮想関数を使える、これは継承である必要があるのでhas-a継承が便利。でないとコールバックの登録や解除に(面倒というのも含めて)悩まされる。関係が固定なのでさらに安全だ。

もっとも、継承先でコールバックを止める必要があるので完全に安全というわけではないけれど、コールバックするくらいなら継承するほうがずっとマシ。さらに多重継承できないと実際に使うのは難しいのでC++専用に近いけど。

3
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?