1

次のような純粋な仮想クラスを検討してください。

class Foo {
    public: virtual int FooBar() = 0;
};

Java開発者は、そのようなものを「インターフェース」と呼ぶでしょう。通常、次にそのインターフェイスにプログラムします。例:(悪い例、申し訳ありません):

class Bar {
    public: Foo f;
};

class Child : public Foo {
    public: int FooBar() { return 1; }
};

Bar b;
b.foo = Child();

クラスFooのインスタンスは構築時に作成されるため、これは明らかにC ++では機能しません(ただし、Fooは抽象クラスであるため、これは不可能です)。

C ++で「インターフェースへのプログラミング」のパターンはありますか?

編集:例を明確にしました、ごめんなさい。

4

6 に答える 6

3

インターフェイス(または抽象クラス)の実装を指す、または参照する何かが必要な場合は、そのインターフェイスへの参照のポインタを使用できます。

class Bar {
public:
    Bar( Foo& af ) : f( af )
    {}
private: 
    Foo& f;
};

参照を使用する場合は、const実装(の)へのFoo& fポインタFoo* fまたはポインタまたはポインタ、あるいはconst実装()へのconstポインタも要件によって異なります。const Foo& fconst Foo* fconst Foo* const f

可能であれば、参照された実装が外部から渡される構成に参照を使用します(私の例のように)。オブジェクトがより集約的であり、含まれているオブジェクト自体によって構築されている場合は、ポインターまたはスマートポインターを使用します。

更新: これまで誰も言及していなかったように、インターフェイスを動的に実装するオブジェクトを割り当てる場合は、基本クラスに仮想デストラクタが必要です。そうしないと、スマートを使用している場合でも、未定義の動作が呼び出されます。ポインタ。また、スマートポインターは便利な場合がありますが、すべてを解決できるわけではないことに注意してください。それでも、所有者の階層を念頭に置いておく必要があります。そうしないと、スマートポインターでは簡単に解決できないサイクルになってしまいます。

于 2012-08-14T10:23:40.670 に答える
3

データメンバーは、へのポインタとして、またはさらに良いことに、への何らかの形式のスマートポインタとしてf宣言する必要があります。FooFooshared_ptr<Foo>

への参照を使用することもできますがFoo、それは事態を複雑にします。クラスには明示的なコンストラクターが必要であり、両方のメンバー関数を明示的に実装しない限り、コピーや割り当てはできません。

于 2012-08-14T10:23:55.977 に答える
3

Javaのようにポリモーフィズムを使用するには、Javaの場合と同様に、ポインターと参照を使用する必要があります。Javaでは、すべてがプリミティブ型または参照のいずれかですFoo f;。Javaで記述すると、参照が取得されます。C ++では、オブジェクトを取得します。

ただし、Javaとは異なり、C++のインターフェイスには仮想関数や基本クラスを含める必要はありません。この良い例は、標準ライブラリで使用されるイテレータインターフェイスです。

于 2012-08-14T10:24:54.940 に答える
2

コンポジションを使わずに「インターフェース」を継承する必要があると思いますよね?

このような

class Bar: public Foo
{
private: 
    virtual int Bar() { /* ... */ }
};

それが「プログラムからインターフェースへ」から私が理解していることです。


編集:ああ、あなたの編集を見て、あなたは本当にここにポインタが必要です。同等のC++コードは次のとおりです。

class Foo {
    public: virtual int Bar() = 0;
};

class Bar {
    //.........v
    public: Foo* f;
};

class Child : public Foo {
    public: int Bar() { return 1; }
};

Bar b;
b.f = new Child();

ただし、に新しく割り当てられたメモリを処理する必要がありますChild()。これを回避し、コードを完全に(論理的に)同等にするために、スマートポインターが必要です。この場合、 -a shared_ptrC ++ 11boost

于 2012-08-14T10:22:24.137 に答える
0

あなたは1つの例外を除いてすべてを正しくやっています。インターフェースから派生する必要があり、メンバーとして含める必要はありません。

class myInterface
{
    virtual void foo() = 0;
}

class iHaveAnInterface: public myInterface
{
    void foo();
}

void iHaveAnInterface::foo()
{
    //implement
}
于 2012-08-14T10:23:09.580 に答える
0

C ++のインターフェイスは、abstract-base-classes:少なくとも1つの純粋仮想関数を含むステートレスクラスとして作成するのが最適です。具象クラスは、インターフェイスクラスからパブリックに派生し、(オプションで)インターフェイスを実装するために状態を追加します。

class IFoo
{
public:
    // enable deletion of implementation classes through IFoo*
    virtual ~IFoo() {}

    // interface
    void bar() 
    { 
        // add optional pre-processing here
        do_bar(); 
        // add optional post-processing here
    }

private:
    // to be overridden by implementation classes
    virtual void do_bar() = 0; // pure virtual

    // no state here!
};

class FooImpl
:
    public IFoo
{
public:
    // constructors, assignment etc. to manipulate state

private:
    virtual void do_bar() 
    { 
         // your implementation 
    }

    // add your state here
};

void my_algorithm(IFoo* foo)
{
    foo->bar();
}

int main()
{
    IFoo* f = new FooImpl();
    my_algorithm(f); // resolves to using FooImpl::do_bar()

    return 0;
}

上記のコードは、実行時のポリモーフィズムと明示的なインターフェイスに関するものです。C ++には、コンパイル時のポリモーフィズムと暗黙的なインターフェイスを使用する代替手段があります。これは、テンプレートと不思議なことに繰り返されるテンプレートパターンを使用して行われます。

ここではNon-Virtual-Interface(NVI)イディオムを使用していることに注意してください。のパブリックインターフェイスIFooは非仮想であり、実装は(純粋な)仮想です。これにより、インターフェイスの作成者は、IFoo::bar()クライアントに気付かれることなく、ログやその他のチェックを内部に追加するなど、より柔軟に対応できます。

于 2012-08-14T10:40:11.257 に答える