C++にはJavaおよびC#のinterface
機能がないため、C++クラスのインターフェイスをシミュレートするにはどうすればよいでしょうか?私の推測では、抽象クラスの複数の継承があります。 メモリのオーバーヘッド/パフォーマンスに関してどのような意味がありますか? SerializableInterface
のようなシミュレートされたインターフェイスの命名規則はありますか?C++でインターフェイスをシミュレートする方法はありますか?
答えて
C++にはC#やJavaとは違って複数の継承があるため、一連の抽象クラスを作成できます。
慣例として、それはあなた次第です。しかし、私はI.
class IStringNotifier
{
public:
virtual void sendMessage(std::string &strMessage) = 0;
virtual ~IStringNotifier() { }
};
とクラス名の前に好きなパフォーマンスは、C#とJavaとの比較の観点から何も心配することはありません。基本的には、関数のルックアップテーブルを持つオーバーヘッドや、仮想メソッドを使用した継承のようなvtableを持つだけです。
抽象クラスを作成する抽象クラスへのポインタを使用してオブジェクトを削除する場合は、仮想デストラクタを使用します。 –
@黄山(Yim Huang):同意して明示的に追加されました。 –
@Michael Aaron Safyan:downvoteに感謝します。コーディングスタイルの好みではなく、回答しているものによって質問を判断した方がいいでしょうか? –
C++のインターフェイスは、純粋な仮想関数のみを持つクラスです。例えば。 :
class ISerializable
{
public:
virtual ~ISerializable() = 0;
virtual void serialize(stream& target) = 0;
};
これはシミュレートされたインターフェイスではなく、Javaのものと同様のインターフェイスですが、欠点はありません。
など。あなたが負の影響なしメソッドとメンバーを追加することができます。
class ISerializable
{
public:
virtual ~ISerializable() = 0;
virtual void serialize(stream& target) = 0;
protected:
void serialize_atomic(int i, stream& t);
bool serialized;
};
命名規則に... C++言語で定義された実際の命名規則はありません。したがって、あなたの環境内のものを選んでください。
オーバーヘッドは1つの静的テーブルであり、まだ仮想関数を持たない派生クラスでは静的テーブルへのポインタです。
私はあなたが仮想コンストラクタを持つことはできないと思います。あなたは仮想デストラクタを持つことができます。 – jkeys
@hooked、入力エラーが修正されました。 – Christopher
デストラクタが純粋な仮想である理由は見当たりません。 単純な仮想で十分でしょう。また、dtorが ではないと宣言しても、定義する必要があります。純粋なバーチャルdtor の場合は、 ISerializable ::〜ISerializable(){} のように、クラス定義の外で定義する必要があります.C++文法では純粋な仮想指定子 とクラス内メンバー関数の両方を使用できないためです定義。 –
仮想継承を使用しない場合は、少なくとも1つの仮想関数を使用する通常の継承よりもオーバーヘッドが悪くならないようにする必要があります。継承された各抽象クラスは、各オブジェクトへのポインタを追加します。
あなたは空の基本クラスの最適化のような何かを行う場合は、あなたがそれを最小限に抑えることができますCの
struct A { void func1() = 0; }; struct B: A { void func2() = 0; }; struct C: B { int i; };
サイズは二つの単語になります。
「メモリのオーバーヘッド/パフォーマンスに関してどのような影響がありますか?」
通常、パフォーマンス上の基準では何も保証されていませんが、仮想呼び出しを使用した場合を除き、通常はありません。
メモリオーバーヘッドでは、「空の基本クラス」最適化により、データメンバーのない基本クラスを追加してもオブジェクトのサイズが増えることはありません。私はあなたがこれをしないコンパイラに対処する必要はないと思うが、私は間違っている可能性があります。
クラスに最初の仮想メンバ関数を追加すると、通常、仮想メンバ関数がない場合と比較して、ポインタのサイズだけオブジェクトが増加します。仮想メンバ関数を追加することで、追加の違いはありません。仮想基底クラスを追加することでさらなる違いが生まれるかもしれませんが、あなたが話していることについては必要ありません。
仮想メンバー関数で複数の基本クラスを追加すると、実際には、通常の実装では複数のvtableポインタが必要になるため、実際には空の基本クラスの最適化が1回だけ行われることを意味します。したがって、各クラスに複数のインターフェイスが必要な場合は、オブジェクトのサイズに追加することができます。
パフォーマンス上、仮想関数呼び出しは、非仮想関数呼び出しよりも少しオーバーヘッドがあります。さらに重要なことに、一般的に(常に?)インライン化されないと想定できます。空の基本コンストラクタとデストラクタは、派生クラスのコンストラクタ/デストラクタコードにインライン化できるため、空の基本クラスを追加することは、通常、構築や破壊にコードを追加しません。
明示的なインターフェイスが必要な場合は仮想機能を回避するためのトリックがありますが、動的なポリモーフィズムは必要ありません。しかし、あなたがJavaをエミュレートしようとしているなら、そうではないと私は想定しています。
例コード:
#include <iostream>
// A is an interface
struct A {
virtual ~A() {};
virtual int a(int) = 0;
};
// B is an interface
struct B {
virtual ~B() {};
virtual int b(int) = 0;
};
// C has no interfaces, but does have a virtual member function
struct C {
~C() {}
int c;
virtual int getc(int) { return c; }
};
// D has one interface
struct D : public A {
~D() {}
int d;
int a(int) { return d; }
};
// E has two interfaces
struct E : public A, public B{
~E() {}
int e;
int a(int) { return e; }
int b(int) { return e; }
};
int main() {
E e; D d; C c;
std::cout << "A : " << sizeof(A) << "\n";
std::cout << "B : " << sizeof(B) << "\n";
std::cout << "C : " << sizeof(C) << "\n";
std::cout << "D : " << sizeof(D) << "\n";
std::cout << "E : " << sizeof(E) << "\n";
}
は出力(32ビットプラットフォーム上でGCC):
A : 4
B : 4
C : 8
D : 8
E : 12
それはC++は、そのJavaの何かを欠落していることではないとして何かを 'シミュレート' する必要は本当にありませんインターフェイスで行うことができます。
Javaは、ビューのC++ポインターから、interface
とclass
の間に「人工的」な区別をします。 interface
は、すべてが抽象的なものであり、データメンバーを含むことのできないメソッドがすべてclass
です。
Javaでは制約のない多重継承はできませんが、class
からimplement
までの複数のインタフェースが許可されているため、この制限が適用されます。
C++では、class
はclass
であり、interface
はclass
です。 extends
は公開継承によって達成され、implements
も公開継承によって達成される。
複数の非インターフェイスクラスから継承すると、余分な問題が発生することがありますが、状況によっては役に立ちます。たった一つの非インターフェイスクラスと完全抽象クラスからの継承クラスのみに制限すると、Java(他のC++/Javaの違いを除いて)と比べて他の困難に遭遇することはありません。
メモリとオーバーヘッドのコストの観点から、Javaスタイルのクラス階層を再作成する場合は、いずれにしてもクラスに仮想関数コストを支払った可能性があります。とにかく、さまざまなランタイム環境を使用しているとすれば、異なる継承モデルのコストの点で、2つの間のオーバーヘッドに根本的な違いはありません。
ところでMSVC 2008は__interfaceというキーワードを持っています。
A Visual C++ interface can be defined as follows:
- Can inherit from zero or more base
interfaces.
- Cannot inherit from a base class.
- Can only contain public, pure virtual
methods.
- Cannot contain constructors,
destructors, or operators.
- Cannot contain static methods.
- Cannot contain data members;
properties are allowed.
この機能はMicrosoft固有です。注意:__interfaceには、インタフェースポインタでオブジェクトを削除する場合に必要な仮想デストラクタはありません。
これはC++を実行するCOM/DCOMの方法であると思います。 –
どうしてそう思う? –
COMインターフェイスで作業しているときは、それが使用されているのを見たのは唯一の場所なので、;-)。 –
C++では、Javaの単純なビヘイビアレスインターフェイスよりもさらに進歩することができます& co。 NVIパターンを使用して明示的な契約(、契約:)を追加することができます。
struct Contract1 : noncopyable
{
virtual ~Contract1();
Res f(Param p) {
assert(f_precondition(p) && "C1::f precondition failed");
const Res r = do_f(p);
assert(f_postcondition(p,r) && "C1::f postcondition failed");
return r;
}
private:
virtual Res do_f(Param p) = 0;
};
struct Concrete : virtual Contract1, virtual Contract2
{
...
};
あなたが求めている方法でインターフェイスを実装する良い方法はありません。完全抽象ISerializable基本クラスのようなアプローチの問題は、C++が多重継承を実装する方法にあります。以下の検討:
class Base
{
};
class ISerializable
{
public:
virtual string toSerial() = 0;
virtual void fromSerial(const string& s) = 0;
};
class Subclass : public Base, public ISerializable
{
};
void someFunc(fstream& out, const ISerializable& o)
{
out << o.toSerial();
}
が明確に意図機能toSerial()は、基本クラスから継承するものを含むサブクラスのメンバーのすべてを直列化するためのものです。問題は、ISerializableからBaseへのパスがないことです。あなたは次のことを実行している場合は、グラフィカルにこれを見ることができます:
void fn(Base& b)
{
cout << (void*)&b << endl;
}
void fn(ISerializable& i)
{
cout << (void*)&i << endl;
}
void someFunc(Subclass& s)
{
fn(s);
fn(s);
}
最初の呼び出しの出力値が2番目の呼び出しが出力する値と同じではありません。どちらの場合もsへの参照が渡されても、コンパイラは渡されたアドレスを適切な基本クラスの型に合わせて調整します。
- 1. C++でWindows入力をシミュレートする方法はありますか?
- 2. Googleマップでイベントをシミュレートする方法はありますか?
- 3. WindowsでLD_LIBRARY_PATHをシミュレートする方法はありますか?
- 4. MySQLでprintステートメントをシミュレートする方法はありますか?
- 5. DynamoDBでBatchWriteItemをシミュレートする方法はありますか?
- 6. JavaインターフェイスでGenericsをオートワイヤリングする方法はありますか?
- 7. キーボード入力をシミュレートする方法はありますか?
- 8. C#DLLからクラスのインターフェイスを実装する方法はありますか?
- 9. インターフェイスにメソッドをオーバーロードする方法はありますか?
- 10. Meegoでプログラムでタッチイベントをシミュレートする方法はありますか?
- 11. VS2010でメディアの信頼をシミュレートする方法はありますか?
- 12. ボットフレームワークエミュレータでグループの会話をシミュレートする方法はありますか?
- 13. javascriptでHTML5のドラッグアンドドロップイベントをシミュレートする方法はありますか?
- 14. MySqlでGROUP BY WITH CUBEをシミュレートする方法はありますか?
- 15. JSで$(this)[0] .filesをシミュレートする方法はありますか?
- 16. Chrome Dev Toolsでモバイルデバイスのハイライトテキストをシミュレートする方法はありますか?
- 17. Cでキープレスをシミュレートする方法
- 18. C#でキープレスをシミュレートする方法
- 19. Google App Engine Python 2.7ランタイムで、GNU Cライブラリのdrem/remainder関数をシミュレートする方法はありますか?
- 20. ポインタを使わずにポインタをシミュレートする方法はありますか?
- 21. Monodevelop Unityでインターフェイス実装テンプレートをオートコンプリートする方法はありますか?
- 22. テスト中に故障したディスクをシミュレートする方法はありますか?
- 23. ミンクのリンク/ボタンのクリックをシミュレートする方法はありますか?
- 24. 私のプラスに小さなiPhoneをシミュレートする方法はありますか?
- 25. SQL Serverのエラー応答/状態をシミュレートする方法はありますか?
- 26. 開発中にdjango collectstaticコマンドをシミュレートする方法はありますか?
- 27. C++でビルドされたアプリケーションへのインターフェイスとしてWebアプリケーションを使用する方法はありますか?
- 28. C#でDateTimeオブジェクトをクローンする方法はありますか?
- 29. クロムエクステンションでC++を使用する方法はありますか?
- 30. インターフェイスを持たないメソッドをモックする方法はありますか?
インタフェースを無効にします。それは否定的な表現のようです。 C++はインタフェースが欠けていません(クラスはインタフェースです)。なぜなら、それはスタンドされていないため、キーワードインタフェースが不足しているだけです。 –
Interfaceキーワードは、コードやデータを含まないことが保証されているため、問題なく簡単に他のインターフェイスとやりとりすることができます。 C++でそのような保証をする方法はありません。それらが競合することを何もしないことを願ってください。 JavaとC#がコードの可読性、相互運用性、理解容易性のために行う多くのことは、C++で作業しているときに遭遇した問題に対応しています。 –
[C++でインターフェイスを宣言する方法は?](http://stackoverflow.com/questions/318064/how-do-you-declare-an-interface-in-c) –