エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

多重継承の使い方の一例

C++の多重継承に熟知された方から見れば(そうでない方でも?)、なにをいまさら感、が漂ってますが、こういう使い方をすれば便利なのか、と気付いたのでメモ。
わたし自身の考えとしては、多重継承はぜんぜん否定していないんですが、うまい使い方というのを知らなかったので、インタフェースを実装する以外ではほとんど使ったことがありませんでした。

それがたまたま、昨日今日ととあるプログラムの実装方法を考えていたときにコレに気がつきました。

インタフェースの一部だけを実装して、最終的に利用するクラスではそれら一部ずつ実装されたクラスを多重継承するというものです。

#include <iostream>

enum ID1 { A, B, C };
enum ID2 { X, Y, Z };

class Foo
{
public:
    virtual ~Foo() {}

    virtual ID1 getID1() const = 0;
    virtual ID2 getID2() const = 0;
};

std::ostream& operator << (std::ostream& out, ID1 id)
{
    switch(id)
    {
    case A:  return out << "A";
    case B:  return out << "B";
    case C:  return out << "C";
    default: return out;
    }
}

std::ostream& operator << (std::ostream& out, ID2 id)
{
    switch(id)
    {
    case X:  return out << "X";
    case Y:  return out << "Y";
    case Z:  return out << "Z";
    default: return out;
    }
}

std::ostream& operator << (std::ostream& out, const Foo& foo)
{
    return out << "(" << foo.getID1() << ", " << foo.getID2() << ")";
}

// ここまでが準備

// ここから具体的な実装

//インタフェースで定義された関数の一部だけ実装する

class FooA : public virtual Foo
{
public:
    ID1 getID1() const { return A; };
};

class FooB : public virtual Foo
{
public:
    ID1 getID1() const { return B; };
};

class FooC : public virtual Foo
{
public:
    ID1 getID1() const { return C; };
};

class FooX : public virtual Foo
{
public:
    ID2 getID2() const { return X; }
};

class FooY : public virtual Foo
{
public:
    ID2 getID2() const { return Y; }
};

class FooZ : public virtual Foo
{
public:
    ID2 getID2() const { return Z; }
};

// 二つの実装を組み合わせて、Fooの仮想関数をすべて実装したクラスを作る

class FooAX : public FooA, public FooX {};
class FooAY : public FooA, public FooY {};
class FooAZ : public FooA, public FooZ {};
class FooBX : public FooB, public FooX {};
class FooBY : public FooB, public FooY {};
class FooBZ : public FooB, public FooZ {};
class FooCX : public FooC, public FooX {};
class FooCY : public FooC, public FooY {};
class FooCZ : public FooC, public FooZ {};

int main(int, char* [])
{
    FooAX ax;
    FooAY ay;
    FooAZ az;
    FooBX bx;
    FooBY by;
    FooBZ bz;
    FooCX cx;
    FooCY cy;
    FooCZ cz;

    std::cout << ax << " " << ay << " " << az << "\n"
              << bx << " " << by << " " << bz << "\n"
              << cx << " " << cy << " " << cz << "\n";

    return 0;
}


実行結果。

(A, X) (A, Y) (A, Z)
(B, X) (B, Y) (B, Z)
(C, X) (C, Y) (C, Z)