C++ のお勉強 テンプレート編

C++ のお勉強三日目。前回の「C++ のお勉強 クラス編」の続き。
三日坊主もイイトコロなので,このテンプレート編が最後のお勉強になる。
C++ は難しいもんだと思ってたけど,今回までで,もう C++ の概要を掴むことが出来た…気がする。C をやっとけば C++ の習得は楽だってウワサは本当らしいね。
あと,本来の目的は L4 のコードを読むことだから,入出力に関しては詳しく調べなかった。

テンプレート関数

  • 例えば,二つの引数を取り大きいほうの数字を返すmax()という関数を作ってみる
    • 関数のオーバーライドを使う:
int max(int a, int b) {
  return (a>b) ? a : b ;
}
double max(double a, double b) {
  return (a>b) ? a : b ;
}
      • これでは,各引数の型毎に関数を定義しなければならない
      • そこで,テンプレート関数を使う
  • 関数の先頭に次のような宣言を付加することで,どんな型でも扱えるテンプレート関数を作成できる
template <テンプレート引数宣言>
    • テンプレート引数は関数宣言や定義の中で型名として使用でき,この型が任意の型に変換される
      • どんな型でも扱え,さらに型安全性が保障される
#include <stdio.h>

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

int main() {
  int a=1, b=2;
  double x=10.0, y= 20.0;
  
  printf("max %d \n", max(a, b));    // => max 2
  printf("max %.1f \n", max(x, y)); // => max 20.0

  //これはエラーになる
  //printf("max %d \n", max(a, x)); 
  //ただし,次のように型を定義できる
  printf("max %d \n", max<int>(a, x)); // => max 10

  return 0;
}

テンプレートクラス

  • テンプレートはクラスでも同様に使える
    • テンプレートクラスのメンバ関数は自動的にテンプレート関数になる
      • もちろん,メンバ関数でさらにテンプレート引数宣言を行ってもいい
    • テンプレートクラスのオブジェクトを作成するときは必ず型を定義する
  • スタックを作るときに使うと便利そう
#include <stdio.h>

template<class X>
class Stack {
  X buf[128];
  int index;
public:
  void push(X var) {
    buf[index++] = var;
  }
  X pop() {
    return buf[--index];
  }
  Stack() {
    index = 0;
  }
};

int main() {
  Stack <int> stack1;
  stack1.push(10);
  stack1.push(20);
  printf("%d \n", stack1.pop()); // => 20
  printf("%d \n", stack1.pop()); // => 10

  Stack <const char *> stack2;
  stack2.push("hoge");
  stack2.push("hage");
  printf("%s \n", stack2.pop()); // => hage
  printf("%s \n", stack2.pop()); // => hoge

  return 0;
}

付録 入出力ストリーム

  • C++ の入出力は,ストリームと呼ばれる流れとして抽象化されている
    • 入出力ストリームは,階層的に構成されたクラスとして定義され,iostream というヘッダファイルに含まれている
  • 例えば,文字を表示するには,次のようにして標準出力にデータを流してやる
std::cout << "hello, world";
    • 出力するデータの形は気にしなくていい
#include <iostream>

int main() {
  std::cout << "hoge"; // => hoge
  std::cout << "10";   // => 10
  std::cout << "0.1";  // => 0.1
  return 0;
}
  • 入出力ストリームは奥が深そうだからこれ以上詮索しない:-)