C++ での Mixin の活用 : Comparable を使って比較演算子を簡単実装

オブジェクト指向プログラミングには Mixin という手法があります。 これを使えば、自作のクラスを比較可能な(Comparable)クラスにすることが簡単に出来ます。 今回は Comparable Mixin を例に C++ での Mixin のやり方について説明します。

Mixin とインターフェース

Mixin の前提として、 多重継承の問題点を把握しておく必要があります。 その辺の話や Mixin の概要に関しては以下の記事をみていただくとして、 C++ に限定して簡単に説明していきます。 多重継承の問題を避けるための代表的な方法はインターフェースです。
class IComparable
{
 public:
  virtual int Compare(const IComparable &other) const = 0;
};
インターフェースの制限は次の 2 つです。 この制限によりインタフェースクラスは多重継承しても問題が発生しないので、クラスに対して自由に継承させられます。
  • 属性(メンバー変数)を持たない
  • 操作(メンバー関数)は宣言のみで実装を持たない(純粋仮想関数)
インターフェースを使うことにはいろんなメリットがあります。
  • 利用側 : 操作(Compare) を持つことが保証される
  • 継承側 : 操作(Compare) の実装が強制される
例えば、ソートのような処理のインプットで ICompareble を指定すれば、 Compare() が使えることが保証されますし、 実際に ICompareble を継承するクラスでは Compare() を実装しないとコンパイルエラーとなります。

cpp_mixin_interface.png


インターフェースはインターフェースで有用です。 ただ、 多重継承で問題になるのは属性を持つことの方で、 操作の実装を禁止する必要はありません。
「操作の実装を持つ」ということは言い換えるとなんらかの「機能を持つ」ということです。 そういったクラスを継承すると元のクラスに機能を付加することになります。 継承によって機能を追加するためのクラスやその手法を Mixinと呼びます。

例えば、『鯨』というクラスを考えてみます。
ほ乳類、魚類から継承したとするとダイヤモンド継承(ひし形継承)と呼ばれる共通の祖先を持つクラスの継承となり、多重継承で最も問題になる形になります。

ダイヤモンド継承

Mixin を用いると「泳げる」(Swimable) という機能を共に持つとみなすことができます。 ダイヤモンド継承は避けられますし、こちらの方がより自然にクラスによるモデル化ができています。

Mixin

Comparable Mixin

Mixin をさらに Comparable(比較できる) Mixin を具体例として説明していきます。


次のような点クラスについて考えてみます。
ちなみに struct はデフォルトが public なことを除いて class と同じものです。
struct Point
{
  int x;
  int y;
};
点クラスのように 等比、比較演算子のオーバーロードを行うと使いやすくなるクラスは多いと思いますが、 毎回それらを実装するのは面倒です。
しかし、 それらの演算子は比較関数から導くことが出来ます。 これを実装したクラスが Comparable Mixin のクラスです。
template <class T>
class ComparableMixIn
{
 public:
  /// 比較用関数
  ///
  /// | 状態               |  戻り値  |
  /// |--------------------|----------|
  /// | other の方が大きい | 負の値   |
  /// | other と一致       |    0     |
  /// | other の方が小さい | 正の値   |
  /// 
  virtual int Compare(const T &other) const = 0;


  // 演算子の実装
  bool operator==(const T &other) const { return Compare(other) == 0; };
  bool operator!=(const T &other) const { return Compare(other) != 0; };
  bool operator< (const T &other) const { return Compare(other) <  0; };
  bool operator<=(const T &other) const { return Compare(other) <= 0; };
  bool operator> (const T &other) const { return Compare(other) >  0; };
  bool operator>=(const T &other) const { return Compare(other) >= 0; };
};
Mixin クラスの特徴は次のようなものです。 インターフェースと同様に属性を持たないので多重継承ができますが、 機能(操作の実装)を持っているところが違います。
  • 属性を持たない
  • キーとなる関数の宣言(純粋仮想関数)
  • キー関数を使って機能となる関数を実装
ここではキーとなる関数は Compare() です。 この Compare() を使って、 比較できる(Comparable)という機能、 すなわち 等比や比較演算子のオーバーロードの実装を行っています。


一方、使う側である点クラスでは ComparableMixIn を継承し、 Compare() を実装します。
ここには実装のちょっとしたテクニックがあります。 ComparableMixIn は継承先の型をとるテンプレートです。こうすることによって継承先の型による演算子のオーバーロードを可能にしています。
struct Point : public ComparableMixIn<Point>
{
   :

  /// 比較関数.
  /// x で比較し、同じなら y で比較
  virtual int Compare(const Point &other) const override
  {
    return ((x != other.x) ? (x - other.x) : (y - other.y));
  }
};
cpp_mixin.png

この Mixin によって、 点クラスは比較の機能をもつことができるようになります。
  Point a(1, 2), b(2, 3);

  cout << boolalpha;
  cout << "a == b : " << (a == b) << endl;
  cout << "a != b : " << (a != b) << endl;
  cout << "a <  b : " << (a <  b) << endl;
  cout << "a <= b : " << (a <= b) << endl;
  cout << "a >  b : " << (a >  b) << endl;
  cout << "a >= b : " << (a >= b) << endl;
実行結果 :
a == b : false
a != b : true
a <  b : true
a <= b : true
a >  b : false
a >= b : false
なお、Boost::Operators を使うと == から != 、 < から他の不等号を定義できます。 厳密に言うと < さえ定義されていれば、 すべての等、不等号 を導くことができます。 (a == b は a < b && b < a)
これは < 演算子をキー関数とした Mixin ということもできます。

ソースファイル

以上のように Comparable Mixin を使うと Compare() を実装するだけで、等号、不等号の機能を簡単に追加することができます。
大したコード量ではありませんが、ヘッダーを公開していますので、ダウンロード(リンク先を保存)して自由に使ってください。[MIT ライセンス]



関連記事
Prev.    Category    Next 

Facebook コメント


コメント

コメントの投稿

Font & Icon
非公開コメント

このページをシェア
アクセスカウンター
アクセスランキング
[ジャンルランキング]
コンピュータ
56位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
9位
アクセスランキングを見る>>
カレンダー(アーカイブ)
プルダウン 降順 昇順 年別

12月 | 2025年01月 | 02月
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31 -


はてな新着記事
はてな人気記事
ブロとも申請フォーム
プロフィール

yohshiy

Author:yohshiy
職業プログラマー。
仕事は主に C++ ですが、軽い言語マニアなので、色々使っています。

はてブ:yohshiy のブックマーク
Twitter:@yohshiy

サイト紹介
プログラミング好きのブログです。プログラミング関連の話題や公開ソフトの開発記などを雑多に書いてます。ただ、たまに英語やネット系の話になることも。