C++ で静的ポリモーフィズムを実装する

Syed Hassan Sabeeh Kazmi 2023年10月12日
  1. C++ での静的ポリモーフィズムのメカニズムを学ぶための不思議な反復テンプレート パターンの理解
  2. ポリシーベースの設計を理解して、C++ での静的メカニズムの有用性を学ぶ
  3. C++ でアーリー バインディング、オーバーロード、またはパラメトリック ポリモーフィズムを使用して静的ポリモーフィズムを実装する
C++ で静的ポリモーフィズムを実装する

静的ポリモーフィズムは、主に C++ のコンテキストで解釈できます。 このチュートリアルでは、重要性、有用性、および C++ で静的ポリモーフィズムを実装する方法について説明します。

C++ の std:sort 関数は、オブジェクト提供のインターフェイス (反復のように動作するオブジェクト) に依存しているため、静的に多態的です。

さらに、インターフェイスの下で提供される反復 (オブジェクト) の正確な動作は、コンパイル時に決定できます。

C++ での静的ポリモーフィズムのメカニズムを学ぶための不思議な反復テンプレート パターンの理解

静的ポリモーフィズムの実装は、優れたコーディング スタイルです。 これを行うには、CRTP を通じてその仕組みを学ぶ必要があります。 速度のために C++ プログラムの柔軟性をいくらか犠牲にしなければならないのは事実です (静的ポリモーフィズムによる)。

技術的なポリモーフィズムの動作を示し、他のタイプとは異なる目標を達成し、何かのタイプに基づいてどのコードを実行して優先順位を付けるかを決定します。

さらに、コンパイラが実装を理解できるように、各翻訳単位でバイナリ コードのサイズが肥大化して検査される可能性のある実装が必要です。

#include <iostream>

template <class Self>
struct Primary {
  Self& self() { return static_cast<Self&>(*this); }

  // an algorithm to perform some function
  int basic_function(int x) {
    self().prologue();
    if (x > 42) x = self().downsize(x);
    x = self().crunch(x);
    self().epilogue();
    return x;
  }

  void prologue() {}

  int downsize(int x) { return x % 42; }

  int crunch(int x) { return -x; }

  void epilogue() {}
};

struct secondary_Derived : Primary<secondary_Derived> {
  int downsize(int x) {
    while (x > 42) x /= 2;
    return x;
  }

  void epilogue() {
    std::cout << "CRTP__ \n"
              << "Process complete! \n";
  }
};

int main() {
  secondary_Derived obj_Dri;
  std::cout << obj_Dri.basic_function(420);
}

出力:

CRTP__
Process complete!
-26

CRTP により、基本クラスは派生クラスに関して情報またはデータを提供できるようになり、ユース ケースの大部分は同じものを表します。 例: Boost の iterator_facade

signatures は CRTP のメンバー関数であり、DerivedClass operator++() {/* Return *this after incrementation */} などはこのメンバー関数から派生しています。

C++ コードで多態的な出力動作が必要な場合は、std::sstreamstd::fstreamstd::cout (型が指定されていない場合でも) は多態性であり、ostream から派生する必要があります。 CRTP は F-bound 定量化の形式であるため、F-bound 多型として知られています。

これにより、柔軟性を犠牲にすることなく仮想機能を実現でき、シミュレートされた動的バインディングと呼ばれることもあります。

Windows STL および WTL ライブラリはこの関数を使用し、Barton-Nackman のトリック は静的ポリモーフィズムの同様の使用法です。これは、C++ コードを最小限に抑える基本クラスに共通の機能を配置できる、制限付きテンプレート拡張 と呼ばれることもあります。 冗長性。

ポリシーベースの設計を理解して、C++ での静的メカニズムの有用性を学ぶ

これは、C++ で静的ポリモーフィズムを実現するための非常に強力な手法の 1つです。 最新の C++ 設計では、ポリシーベースのクラスまたはポリシーベースのプログラミングは、ポリシーと呼ばれる C++ のイディオムに基づく設計アプローチです。

戦略パターンのコンパイル時のバリアントは、モジュール性を高め、直交する設計上の決定を強調します。

革新を表す比較的低いレベルで個々のクラスの動作を定義しますが、交換可能なモジュールからソフトウェア コンポーネントを組み立てることは、決して新しい概念ではありません。

#include <windows.h>

#include <iostream>

struct color_code {
  void pri_color() { this->reveal_colorCode(); }

  void reveal_colorCode() {
    std::cout << "The color code is revealed!" << std::endl;
  }
};

struct banner_code {
  void pri_color() {
    std::cout << "The banner code is revealed to the officials!" << std::endl;
  }
};

template <class code_type>

class Info : public code_type {
 public:
  void code_implementation() { code_type::pri_color(); }
};

int main() {
  Info<color_code> lordcommander;
  lordcommander.code_implementation();

  Info<banner_code> kingslayer;
  kingslayer.code_implementation();
  return 0;
}

出力:

The color code is revealed!
The banner code is revealed to the officials!

これにより、コンパイル時にパターン (テンプレート メソッド パターンなど) を再解釈して、メイン クラスにスケルトン アルゴリズムを持たせ、個々のポリシーの適切な関数を (カスタマイズ ポイントで) 呼び出すことができます。

一般に、これらの設計は継承を必要とせず、その機能のほとんどは静的ポリフォミック動作を反映しています。

C++ でアーリー バインディング、オーバーロード、またはパラメトリック ポリモーフィズムを使用して静的ポリモーフィズムを実装する

そのオブジェクト メソッドはコンパイル時に呼び出され、通常は演算子と関数のオーバーロードを使用して実装されます。

メソッドのオーバーロードはコンパイル時のポリモーフィズムであり、複数のメソッドが同じ名前で異なるパラメーター リストと型を持つことができます。

メソッドはコンパイル時に認識されるため、パフォーマンスが向上します。これにより、実行が高速化されますが、ソリューションを実装する際の柔軟性が低下します。

関数のオーバーロードと演算子のオーバーロードは、コードの機能を拡張するためのオーバーロード機能を提供するため、静的ポリモーフィズムの動作を反映しています。

#include <windows.h>

#include <iostream>

// parametric polymorphism
template <class T>

T max(T a, T b) {
  return a > b ? a : b;
}

// early binding | static binding
class Base {
 public:
  void show() { std::cout << "\nIn Base \n"; }
};

class Derived : public Base {
 public:
  void show() { std::cout << "In Derived \n"; }
};

// override
void swap(int* a, int* b){

};

void swap(double* a, double* b){

};

int main() {
  int x = 10, y = 20;
  double a = 1.2, b = 3.4;

  // overloading | as static polymorphism
  swap(&x, &y);  // swap(int,int)
  swap(&a, &b);  // swap(double, double)

  // parametric polymorphism | as static polymorphism
  std::cout << ::max(9, 5) << std::endl;

  std::string foo("kingslayer"), bar("widow'swale");
  std::cout << ::max(foo, bar) << std::endl;

  // early binding or static binding | as static polymorphism
  Base* bp = new Derived;
  bp->show();

  return 0;
}

出力:

9
widow'swale

In Base

UML ダイアグラムは、ポリモーフィズムがどのように処理されるかを直接記述することはできませんが、少なくとも部分的に静的または動的に実装できます (OOP モデルの静的ポリモーフィズムの依存関係によって異なります)。

静的ポリモーフィズムの動作が実行時ではなくコンパイル時に発生する場合、間接呼び出しのパフォーマンスへの影響を取り除くことができます。

最も重要なことは、パフォーマンスが静的ポリモーフィズムの主な利点であり、PBD (ポリシー ベースの設計) と CRTP (Curiously Recurring Template Pattern) がその完璧な例であり、この手法がいかに強力であるかを強調しています。

コンパイラとオプティマイザに非常に重要な情報を大量に提供し、コンパイル時に前提条件をチェックし、プログラムの実行に重要なオプションを選択できます。

Syed Hassan Sabeeh Kazmi avatar Syed Hassan Sabeeh Kazmi avatar

Hassan is a Software Engineer with a well-developed set of programming skills. He uses his knowledge and writing capabilities to produce interesting-to-read technical articles.

GitHub