2012-01-03 24 views
8

私は通常C#でプログラムを作成しますが、C++を少しやろうとしていますが、C++でインターフェイスを実装しようとすると多少苦労しています。C++でインターフェイスを実装する

は、C#では私はこのような何かしたい:Cで

class Base<T> 
{ 
    public void DoSomething(T value) 
    { 
     // Do something here 
    } 
} 

interface IDoubleDoSomething 
{ 
    void DoSomething(double value); 
} 

class Foo : Base<double>, IDoubleDoSomething 
{ 
} 

を++、私はこのようにそれを実装しました:

template <class T> 
class Base 
{ 
public: 
    virtual void DoSomething(T value) 
    { 
     // Do something here 
    } 
}; 

class IDoubleDoSomething 
{ 
public: 
    virtual void DoSomething(double value) = 0; 
}; 

class Foo : public Base<double>, public IDoubleDoSomething 
{ 
}; 

問題は、それがあるので、私ははFooのインスタンスを作成することができないということです抽象的(DoSomethingを実装していません)。私はDoSomethingを実装することができ、Baseのメソッドを呼び出すことができることを認識していますが、これを実行するより良い方法があることを期待していました。私は異なるデータ型の基底から継承する他のクラスを持っていて、Baseを使用しないIDoubleDoSomethingから継承する他のクラスを持っています。

助けてください。

+2

これで悪く何が、どのような方法でそれは「より良い」だろうか? –

+2

"Foo"がBaseからメソッドを継承し、実装が必要ないC#バージョンのように "より良い"ものが動作すると思います。 FooのBaseから各メソッドを実装するのは本当に悪いことではないと思います。 – Clueless

+0

これは面倒ですが、より良い方法は見つけられませんでした。( –

答えて

1

他の人が指摘したように、基本クラスの2つの関数は、共通の基本クラスを持たないため、(名前と引数の型が同じであっても)無関係です。それらを関連付けるには、それらに共通の基本クラスを与える必要があります。

また、複数の継承が正しく機能するようにするには、非プライベートベースクラスをvirtualとして宣言する必要があります。さもなければ、共通の基底クラス(これはしばしばこのスタイルのコードが必要です)を持っていれば、悪いことが起こります。

だから、次のようにあなたはあなたの例の作品を作ることができる、ことを考える:

template <class T> 
class IDoSomething { 
public: 
    virtual void DoSomething(T value) = 0; 
}; 

template <class T> 
class Base : public virtual IDoSomething<T> 
{ 
public: 
    virtual void DoSomething(T value) 
    { 
     // Do something here 
    } 
}; 

class IDoubleDoSomething : public virtual IDoSomething<double> 
{ 
}; 

class Foo : public virtual Base<double>, public virtual IDoubleDoSomething 
{ 
}; 
+0

これは私が達成しようとしていたものに最も近いと思われます。私は 'Base'を所有しているので、私のシナリオではうまくいきます。もし私が 'Base'の所有者でなければ、他の解決法がより適用可能であると思います。 – Clueless

2

は、次のC++コードを使用すると、それがIDoSomething1IDoSomething2を実装せずにFooを使用することができますC++では

class Foo 
{ 
public: 
    void DoSomething1(){} 
}; 

template<typename t> 
void MethodExpectsDosomething1(t f) 
{ 
    f.DoSomething1(); 
} 

template<typename t> 
void MethodExpectsDosomething2(t f) 
{ 
    f.DoSomething2(); 
} 

int main() 
{ 
    Foo f; 
    MethodExpectsDosomething1<Foo>(f); 

    MethodExpectsDosomething2<Foo>(f); 

    return 0; 
} 

を考えてみましょう。 2番目の方法MethodExpectsDosomething2は、FooにはDoSomething2メソッドがないため、単にコンパイルできません。

C#では、このような構成は可能ではなく、IDoSomething1およびIDoSomething2インターフェイスを持ち、それをtype constraintとして指定します。

あなたのコードを見て、そのようなインターフェイスがまったく必要かどうかを確認する必要がありますか?

+0

ダックタイピングの問題は、自己文書化ではなく、多形性を伴う解決策が自己文書化していることです。 – akappa

+0

アヒルタイピングがそうだったら悪い... C#4.0は 'dynamic'キーワードとして導入されていないでしょう。あなたが斧を与えられただけであなたの足をチョップしなければならないという意味ではありません。 –

+0

私はあなたに「それは普及しているあなたがテンプレート化された関数のユーザであれば、どのような種類の機能があなたのオブジェクトからの要求を機能させるか、そしてどのセマンティクスを使っているのかをどのように把握していますか?この問題は動的多型、インターフェイスはドキュメントなので、 – akappa

-1

他のすべてが整えられていれば、これはうまくいくはずです。

元のコードでは、Fooは2つのvoid DoSomething(double value)メソッド(1つは抽象的な)を持っています。 これは、ベース部分とIDoubleDoSomething部分です。 Foo :: BaseとFoo :: IDoubleDoSomething。 IDoubleDoSomething.DoSomething()に一時的に与えて実装することで試すことができます。

しかし、fooがすでにベース」あなたはIDoubleDoSomethingせずに必要なものを持っている「である」ため、

+2

インターフェイスを使用する理由は、ベースクラスまたは派生クラスの定義を必要とせずに、インターフェイスにポインタを渡すためです。インターフェイスクラスを削除することは逆向きに進んでいます。 –

2

C++では、純粋仮想関数は常に派生クラスでオーバーライドする必要があります。。彼らは、他の基地からのオーバーライドを継承することはできません動的多型が必要な場合は関数を呼び出すFooに関数を書くのに賢明な選択肢はないと思います。Base関数は仮想である必要はありません。

これらのクラスの使用方法(特に、インターフェイスの各インスタンスの実際の型がコンパイル時にわかっているかどうか)によっては、静的多態性を使用して、特定の実装クラスをそのユーザーに注入できますテンプレートパラメータとして;例えば:

// No explicit interface specification with static polymorphism 
class Foo : public Base<double> 
{ 
    // Inherits DoSomething(double) 
}; 

// Template can used with any class that impelements a 
// "DoSomething" function that can accept a double. 
template <class DoubleDoSomething> 
void DoSomethingWithDouble(DoubleDoSomething & interface, double value) 
{ 
    interface.DoSomething(value); 
} 

// This particular specialisation uses a "Foo" object. 
Foo foo; 
DoSomethingWithDouble(foo, 42); 
2

事は、この内の任意の純粋仮想関数が存在しなかった場合でも、あなたはとにかく、FooオブジェクトにDoSomethingを呼び出すことができないだろう(Base::DoSomethingIWhatever::DoSomethingは、2つの無関係な機能であり、あります)。 Baseはこれを動作させるにはIWhateverから継承する必要があります。

あなたが実際にこれを必要とするかどうかは自問自答します。テンプレート(そして概念、それは一種のインタフェースです - Boost.ConceptCheckを参照してください)を使った一般的なプログラミングは、通常、実行時のサブタイプ多型よりもC++で優れた解決策です。 (それは、例えばIDoSomething<double>だ)あなたがIDoubleDoSomethingをtemplatiseことができ、余分なボーナスポイントのために

template <typename T, class Interface> 
class Base : public Interface { ... }; 

class Foo : public Base<double, IDoubleDoSomething> { ... }; 

、またはに特性クラスを使用します。

2

は、あなたはそれがあるインターフェイスを実装し、ベースに第2のテンプレートパラメータを渡すことができますタイプTを関連するインタフェースにマップする。

関連する問題