C++ インターフェイス (抽象クラス) && プロセッサ

名前: Ah Yue's Little Dongdon

学習: Python、C/C++

ホームページのリンク: A Yue's Xiaodongdong の blog_CSDN blog-python&&c++ の高度な知識、旧正月に必須、C/C++ 知識の説明分野のブロガー

目次

C++インターフェース

抽象クラスのインスタンス

デザイン戦略

プリプロセッサ

#前処理を定義する

パラメータマクロ

条件付きコンパイル

# および ## 演算子


 

C++インターフェース

インターフェイスは、クラスの特定の実装を必要とせずに、クラスの動作と機能を記述します。

C++ インターフェイスは、抽象クラスを使用して実装されます。抽象クラスをデータ抽象化と混同しないでください。データ抽象化は、実装の詳細を関連データから分離する概念です。

クラス内の少なくとも 1 つの関数が純粋仮想関数として宣言されている場合、クラスは抽象クラスです。純粋仮想関数は、次のように宣言で「= 0」を使用して指定します。

class Box
{
   public:
      // 纯虚函数
      virtual double getVolume() = 0;
   private:
      double length;      // 长度
      double breadth;     // 宽度
      double height;      // 高度
};

抽象クラス(一般に ABC と呼ばれる) を設計する目的は、継承元となる適切な基本クラスを他のクラスに提供することです。抽象クラスはオブジェクトのインスタンス化には使用できず、インターフェイスとしてのみ使用できます抽象クラスのオブジェクトをインスタンス化しようとすると、コンパイル エラーが発生します。

したがって、ABC のサブクラスをインスタンス化する必要がある場合は、各純粋仮想関数を実装する必要があります。これは、C++ がインターフェイスを宣言するための ABC の使用をサポートしていることも意味します。純粋仮想関数が派生クラスでオーバーライドされていない場合、このクラスのオブジェクトをインスタンス化しようとするとコンパイル エラーが発生します。

オブジェクトのインスタンス化に使用できるクラスは、具象クラスと呼ばれます。

抽象クラスのインスタンス

次の例を参照してください。基本クラス Shape はインターフェイス getArea()を提供し、 getArea() は2 つの派生クラス Rectangle および Triangle にそれぞれ実装されています 

#include <iostream>
 
using namespace std;
 
// 基类
class Shape 
{
public:
   // 提供接口框架的纯虚函数
   virtual int getArea() = 0;
   void setWidth(int w)
   {
      width = w;
   }
   void setHeight(int h)
   {
      height = h;
   }
protected:
   int width;
   int height;
};
 
// 派生类
class Rectangle: public Shape
{
public:
   int getArea()
   { 
      return (width * height); 
   }
};
class Triangle: public Shape
{
public:
   int getArea()
   { 
      return (width * height)/2; 
   }
};
 
int main(void)
{
   Rectangle Rect;
   Triangle  Tri;
 
   Rect.setWidth(5);
   Rect.setHeight(7);
   // 输出对象的面积
   cout << "Total Rectangle area: " << Rect.getArea() << endl;
 
   Tri.setWidth(5);
   Tri.setHeight(7);
   // 输出对象的面积
   cout << "Total Triangle area: " << Tri.getArea() << endl; 
 
   return 0;
}

上記のコードをコンパイルして実行すると、次の結果が生成されます。

長方形の合計面積: 35
三角形の合計面積: 17

上記の例から、抽象クラスがインターフェイス getArea() を定義する方法と、2 つの派生クラスが面積を計算するための異なるアルゴリズムを通じて同じ関数をどのように実装するかがわかります。

デザイン戦略

オブジェクト指向システムは、抽象基本クラスを使用して、すべての外部アプリケーションに適切で共通の標準化されたインターフェイスを提供する場合があります。次に、派生クラスは、抽象基本クラスを継承することによって、同様の操作をすべて継承します。

外部アプリケーションによって提供される関数 (つまり、パブリック関数) は、抽象基本クラス内の純粋な仮想関数として存在します。これらの純粋仮想関数は、対応する派生クラスに実装されます。

このアーキテクチャにより、システムが定義された後でも、新しいアプリケーションをシステムに簡単に追加できます。

プリプロセッサ

プロセッサは、実際のコンパイルの前にどのような前処理を行うべきかをコンパイラに指示する命令です。

すべてのプリプロセッサ ディレクティブはシャープ記号 (#) で始まり、プリプロセッサ ディレクティブの前に使用できるのはスペース文字のみです。前処理ディレクティブは C++ ステートメントではないため、セミコロン (;) で終わりません。

これまでのすべての例に #include ディレクティブがあることがわかりました。このマクロは、ヘッダー ファイルをソース ファイルにインクルードするために使用されます。

C++ は、#include、#define、#if、#else、#line などの多くの前処理ディレクティブもサポートしています。これらの重要なディレクティブを見てみましょう。

#前処理を定義する

#define 前処理ディレクティブは、シンボリック定数を作成するために使用されます。この記号定数は通常マクロと呼ばれ、命令の一般的な形式は次のとおりです。

#define マクロ名の置換テキスト

このコード行がファイルに出現すると、プログラムがコンパイルされる前に、ファイル内に出現する後続のすべてのマクロが置換テキストに置き換えられます。例えば:

#include <iostream>
using namespace std;
 
#define PI 3.14159
 
int main ()
{
 
    cout << "Value of PI :" << PI << endl; 
 
    return 0;
}

次に、このコードをテストして、前処理の結果を確認してみましょう。ソース コード ファイルがすでに存在すると仮定して、-E オプションを使用してコンパイルし、結果を test.p にリダイレクトします。ここで、test.p ファイルを見ると、すでに多くの情報が含まれており、ファイルの下部の値が次のように変更されていることがわかります。

$ gcc -E test.cpp > test.p

...
int main ()
{
 
    cout << "Value of PI :" << 3.14159 << endl; 

    return 0;
}

パラメータマクロ

#define を使用すると、次のようなパラメータを含むマクロを定義できます。

#include <iostream>
using namespace std;
 
#define MIN(a,b) (a<b ? a : b)
 
int main ()
{
   int i, j;
   i = 100;
   j = 30;
   cout <<"较小的值为:" << MIN(i, j) << endl;
 
    return 0;
}

上記のコードをコンパイルして実行すると、次の結果が生成されます。

小さい値: 30

条件付きコンパイル

プログラム ソース コードの一部を選択的にコンパイルするために使用できるディレクティブがいくつかあります。このプロセスは条件付きコンパイルと呼ばれます。

条件付きプリプロセッサの構造は、if 選択構造と非常によく似ています。次のプリプロセッサ コードを考えてみましょう。

#ifdef NULL 
   #define NULL 0 
#endif

デバッグ時のみコンパイルできます。デバッグ スイッチは次のようなマクロで実装できます。

#ifdef デバッグ
   cerr <<"変数 x = " << x << endl; 
#endif

#ifdef DEBUG 指令の前に記号定数 DEBUG が定義されている場合、プログラム内の cerrステートメントは コンパイルされます。次のように #if 0 ステートメントを使用してプログラムの一部をコメントアウトできます。

#if 0 
#endif
   をコンパイルしないコード

次の例を試してみましょう。

#include <iostream>
using namespace std;
#define DEBUG
 
#define MIN(a,b) (((a)<(b)) ? a : b)
 
int main ()
{
   int i, j;
   i = 100;
   j = 30;
#ifdef DEBUG
   cerr <<"Trace: Inside main function" << endl;
#endif
 
#if 0
   /* 这是注释部分 */
   cout << MKSTR(HELLO C++) << endl;
#endif
 
   cout <<"The minimum is " << MIN(i, j) << endl;
 
#ifdef DEBUG
   cerr <<"Trace: Coming out of main function" << endl;
#endif
    return 0;
}

上記のコードをコンパイルして実行すると、次の結果が生成されます。

トレース: main 関数内
最小値は 30
トレース: main 関数から出てくる

# および ## 演算子

# および ## 前処理演算子は、C++ と ANSI/ISO C の両方で使用できます。# 演算子は、置換テキスト トークンを引用符で囲まれた文字列に変換します。

次のマクロ定義を参照してください。

#include <iostream>
using namespace std;
 
#define MKSTR( x ) #x
 
int main ()
{
    cout << MKSTR(HELLO C++) << endl;
 
    return 0;
}

上記のコードをコンパイルして実行すると、次の結果が生成されます。

こんにちはC++

どのように機能するかを見てみましょう。当然のことながら、C++ プリプロセッサは次の行を挿入します。

cout << MKSTR(HELLO C++) << endl;

に変換:

cout << "HELLO C++" << endl;

## 演算子は、2 つのトークンを連結するために使用されます。以下に例を示します。

#define CONCAT( x, y ) x ## y

CONCAT がプログラム内に出現すると、その引数が連結されてマクロの代わりに使用されます。たとえば、次の例に示すように、プログラム内の CONCAT(HELLO, C++) は「HELLO C++」に置き換えられます。

#include <iostream>
using namespace std;
 
#define concat(a, b) a ## b
int main()
{
   int xy = 100;
   
   cout << concat(x, y);
   return 0;
}

上記のコードをコンパイルして実行すると、次の結果が生成されます。

100

どのように機能するかを見てみましょう。当然のことながら、C++ プリプロセッサは次の行を挿入します。

cout << concat(x, y);

に変換:

cout << xy;

おすすめ

転載: blog.csdn.net/m0_64122244/article/details/132278198