6
class IA
{
public:
    virtual void a() = 0;
};

class A: virtual public IA
{
public:
    virtual void a()
    {
    }
};

class IB: virtual public IA
{
public:
    virtual void b() = 0;
};

class B: virtual public IB, public A
{
public:
    virtual void b()
    {
    }
};

上記のように、常にインターフェイスを仮想として継承しますか? そうでない場合、上記のコードをどのように実装しますか?

4

2 に答える 2

3

多重継承と仮想継承を組み合わせて使用​​することは、インターフェイスと実装の階層を分離する場合に適切な設計上の選択です。たとえば、次を参照してください


長所:

  • コードの重複が少ない: インターフェイスの実装が再利用可能に
  • クラスのインターフェース実装間の切り替えは簡単です
  • 基本クラスを見るだけで、具体的な実装について多くのことがわかります

短所:

  • 仮想継承によるディスパッチ パフォーマンスの低下
  • 珍しいパターン、外部/新しい人のために説明/文書化する必要があります

代替案:

  • インターフェイス階層が必要な場合、適切な代替手段はありません

  • そうしないと、階層が個々のインターフェイスに分割される可能性があります

次のようになります。

struct IA
{
    virtual ~IA() = default;
    virtual void a() = 0;
};

struct A: public IA
{
    virtual ~A() = default;
    virtual void a() {}
};

struct IB
{
    virtual ~IB() = default;
    virtual void b() = 0;
};

struct B: public IB
{
    virtual ~B() = default;
    virtual void b() {}
};

struct C: public A, public B
{
};
于 2016-12-29T10:11:43.190 に答える
2

比較的クリーンな回避策が 1 つあります。IBからBを継承する場合、コンパイラは、 IAを含むIBからのすべての抽象メソッドの実装を提供することを要求します。a() はすでにAに実装されているため、単純にAからメソッドを呼び出すスタブをBに作成できます。

class IA
{
public:
    virtual void a() = 0;
};

class A: public IA
{
public:
    virtual void a()
    {
    }
};

class IB: public IA
{
public:
    virtual void b() = 0;
};

class B: public IB, public A
{
public:
    virtual void b()
    {
    }

    virtual void a()
    {
        A::a();
    }
};
于 2012-06-26T13:07:37.613 に答える