web-dev-qa-db-ja.com

C ++の抽象クラスとインターフェイス

可能性のある複製:
C++でインターフェイスをどのように宣言しますか?

これは、C++に関する一般的な質問です。ご存知のように、JavaやC#とは異なり、C++ではinterfaceabstract classの間に明確な区別はありません。 C++でabstract classの代わりにinterfaceを使用することがより望ましいのはいつですか?例を挙げていただけますか?

90
fatma.ekici

interfaceでは、pure virtualメソッドのみを持つ(つまりコードなしの)C++クラスを意味すると思います)、代わりにabstract classを使用すると、オーバーライド可能な仮想メソッドと一部のコードを含むC++クラスを意味しますが、atクラスをインスタンス化できないようにする少なくとも1つの純粋仮想メソッド。例えば。:

class MyInterface
{
public:
  // Empty virtual destructor for proper cleanup
  virtual ~MyInterface() {}

  virtual void Method1() = 0;
  virtual void Method2() = 0;
};


class MyAbstractClass
{
public:
  virtual ~MyAbstractClass();

  virtual void Method1();
  virtual void Method2();
  void Method3();

  virtual void Method4() = 0; // make MyAbstractClass not instantiable
};

Windowsプログラミングでは、interfacesCOMの基本です。実際、COMコンポーネントはインターフェースのみをエクスポートします(つまり、v-tablesへのポインター、つまり関数ポインターのセットへのポインター)。これは、ABI(Application Binary Interface)を定義するのに役立ちます。 C++でCOMコンポーネントをビルドしてVisual Basicで使用するか、CでCOMコンポーネントをビルドしてC++で使用するか、Visual C++バージョンXでCOMコンポーネントをビルドしてVisual C++バージョンYで使用します。クライアントコードとサーバーコードを高度に分離するインターフェイス。

さらに、 この記事 で説明されているように、C++オブジェクト指向インターフェイス(純粋なC DLLの代わりに)を使用してDLLを構築する場合、インターフェイスをエクスポートすることをお勧めします(「成熟したアプローチ」)C++クラスの代わりに(これは基本的にCOMが行うことですが、COMインフラストラクチャの負担はありません)。

具体的な特定の動作を指定せずに、コンポーネントをプログラムできるルールのセットを定義する場合は、interfaceを使用します。このインターフェイスを実装するクラスは、いくつかの具体的な動作自体を提供します。

代わりに、デフォルトのインフラストラクチャコードと動作を提供するときに抽象クラスを使用し、この抽象クラスから派生するクライアントコード、純粋な仮想メソッドをカスタムコードでオーバーライドし、completeこの動作をカスタムコードでオーバーライドします。たとえば、OpenGLアプリケーションのインフラストラクチャを考えてください。 OpenGLの初期化、ウィンドウ環境の設定などを行う抽象クラスを定義できます。次に、このクラスから派生して、たとえばレンダリングプロセスとユーザー入力の処理:

// Abstract class for an OpenGL app.
// Creates rendering window, initializes OpenGL; 
// client code must derive from it 
// and implement rendering and user input.
class OpenGLApp
{
public:
  OpenGLApp();
  virtual ~OpenGLApp();
  ...

  // Run the app    
  void Run();


  // <---- This behavior must be implemented by the client ---->

  // Rendering
  virtual void Render() = 0;

  // Handle user input
  // (returns false to quit, true to continue looping)
  virtual bool HandleInput() = 0;

  // <--------------------------------------------------------->


private:
  //
  // Some infrastructure code
  //
  ... 
  void CreateRenderingWindow();
  void CreateOpenGLContext();
  void SwapBuffers();
};


class MyOpenGLDemo : public OpenGLApp
{
public:
  MyOpenGLDemo();
  virtual ~MyOpenGLDemo();

  // Rendering
  virtual void Render();  // implements rendering code

  // Handle user input
  virtual bool HandleInput(); // implements user input handling


  //  ... some other stuff
};
131
Mr.C64

interfaceは主にJavaで人気がありました。
以下はinterfaceの性質とそのC++の同等物です。

  1. interfaceには、ボディのない抽象メソッドのみを含めることができます。 C++に相当するものは純粋なvirtualメソッドですが、ボディを持つことはできますが、できません。
  2. interfaceにはstatic finalデータメンバーのみを含めることができます。同等のC++は、コンパイル時定数であるstatic constデータメンバーです。
  3. 複数のinterfaceは、Java implementによってclassedにすることができます。Java classは1つのclassしか継承できないため、この機能が必要です。 C++は、必要に応じてvirtualキーワードの助けを借りて、すぐに多重継承をサポートします

ポイント3のため、interfaceの概念はC++で正式に導入されたことはありません。それでも、それを行うための柔軟性を持つことができます。

これに加えて、このトピックでBjarneの FAQ を参照できます。

31
iammilind

一般的な実装が必要な場合、抽象クラスが使用されます。インターフェイスは、プログラムの一部も準拠する必要があるコントラクトを指定したい場合になります。インターフェイスを実装することにより、特定のメソッドを実装することが保証されます。抽象クラスを拡張することにより、その実装の一部を継承しています。したがって、インターフェースはメソッドが実装されていない単なる抽象クラスです(すべて純粋な仮想です)。

15
Will

純粋仮想関数は、主に以下を定義するために使用されます。

a)抽象クラス

これらは、それらから派生し、純粋な仮想関数を実装する必要がある基本クラスです。

b)インターフェース

これらはすべての関数が純粋仮想である「空の」クラスであるため、すべての関数を派生して実装する必要があります。

純粋仮想関数は、実際には基本クラスに実装がなく、派生クラスに実装する必要がある関数です。

2
user1740176

メンバーをインターフェースに入れないでください。言い方は正しいですが。インターフェイスを「削除」しないでください。

class IInterface() 
{ 
   Public: 
   Virtual ~IInterface(){}; 
   … 
} 

Class ClassImpl : public IInterface 
{ 
    … 
} 

Int main() 
{ 

  IInterface* pInterface = new ClassImpl(); 
  … 
  delete pInterface; // Wrong in OO Programming, correct in C++.
}
0
zhouchen