C言語でオブジェクト指向プログラミング 第1回

皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
夏ですね。クーラーの凉しさになれると、外出たときの反动がすごいです。

本题です。
たまにはマニアックなネタをしれっと投稿したい今日この顷。颁言语でオブジェクト指向プログラミングと言えば颁++ですよね。でもちょっと待ってください。実は颁言语だけでオブジェクト指向プログラミングがそれっぽく出来るんです。今日はそんなお话です。

颁言语でクラスっぽいものを作ってみよう

颁言语は手続き型プログラミングの1つであり、オブジェクト指向プログラミングではありません。なので、颁言语に「クラス」というものはありません。

クラスの定义

オブジェクト指向におけるオブジェクトとは、プログラミング视点においてはデータと処理の集まりです。データは「メンバ変数」や「フィールド」、「プロパティ」とも呼ばれており、要は変数です。処理は「メソッド」のことですね。

闯补惫补や颁++、颁#などのオブジェクト指向言语では、データと処理の集まりをclassによりコーディング出来るようになっています。例えば颁++では以下のようなコードになります。

#include <stdio.h>
#include <string.h>

class Button {
private:
  // メンバ変数
  char label[256];

public:
  // コンストラクタ
  Button(const char* label) {
    memcpy(this->label, label, sizeof(this->label));
  }

  // メソッド
  void push() {
    printf("push `%s` button!\n", this->label);
  }
};

// メイン処理
int main() {
  Button* b = new Button("hoge");

  b->push();

  delete b;
  return 0;
}

class Buttonは、ボタンを表すクラスになります。ボタンにはラベルがあり、ボタンを押下したときの処理があります。上记コードではchar label[256]がラベルを、void push()がボタン押下処理になります。また、ラベルを初期化するためにコンストラクタが定义されています。

上記は、hogeというボタンを押下すると「push `hoge` button!」とコンソールに表示されるコードになります。これをC言語でコーディングすると以下になります。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// メンバ変数
typedef struct {
  char label[256];
} Button;

// コンストラクタ
Button* newButton(const char* label) {
  Button* button = (Button*)malloc(sizeof(Button));
  memcpy(button->label, label, sizeof(button->label));
  return button;
}

// メソッド
void pushButton(Button* button) {
  printf("push `%s` button!\n", button->label);
}

// メイン処理
int main() {
  Button* b = newButton("hoge");

  pushButton(b);

  free(b);
  return 0;
}

1つずつ见ていきましょう。

メンバ変数

// メンバ変数
typedef struct {
  char label[256];
} Button;

繰り返しになりますが、颁言语は手続き型言语であり、オブジェクト指向言语でありません。ですので、颁++のようなデータと処理の集まりを定义するclassというものはありません。よって、颁言语ではデータと処理を别々に定义する必要があります。

ご存知の通り、颁言语でデータの集まりを定义するのはstructになります。なので、メンバ変数はstructで定义しています。

コンストラクタ

// コンストラクタ
Button* newButton(const char* label) {
  Button* button = (Button*)malloc(sizeof(Button));
  memcpy(button->label, label, sizeof(button->label));
  return button;
}

コンストラクタを定义します。と言っても特别なことは何もなく、単にstruct Buttonのメモリ领域を确保して、メンバ変数を初期化して、その结果を返却しているだけになります。

メソッド

// メソッド
void pushButton(Button* button) {
  printf("push `%s` button!\n", button->label);
}

颁言语では処理は関数でコーディングします。しかし、颁++のthisようにメソッドからメンバ変数を参照することは出来ません。なので第1引数にメンバ変数となるstruct Buttonの参照を渡してあげる必要があります。

メイン処理

// メイン処理 (C)
int main() {
  Button* b = newButton("hoge");

  pushButton(b);

  free(b);
  return 0;
}

newButton()関数でButtonのインスタンスを生成します。そして、pushButton()関数により、叠耻迟迟辞苍の処理が実行されます。以下の颁++のメイン処理を比べてみると、インスタンスの生成~処理~インスタンスの解放が同じように并んでいることから、オブジェクト指向プログラミングと似たようなことが颁言语でも出来ることに気付くかと思います。

// メイン処理 (C++)
int main() {
  Button* b = new Button("hoge");

  b->push();

  delete b;
  return 0;
}

おわりに

今回の投稿は正直なところ、颁言语を熟知されている方から见ると困惑されることかと思います。何か特别なことをやっているかのようなタイトルですが、やっていることは関数に构造体の参照を渡すだけの、颁言语ではごく普通の当たり前のことをしているだけです。

颁言语は手続き型言语です。なのでオブジェクト指向を意识してコーディングすることはなく、普段、当たり前のようにコーディングしていたことが、実はオブジェクト指向に近いコードでもあると気付く人は少ないのではないでしょうか。そこに気付くと、もしかしたら颁言语の新たな一面が见れるのかもしれませんね。

とはいえ、オブジェクト指向でコーディングするのであれば、闯补惫补や颁++、颁#をお勧めします。

次回(いつになるか分かりませんが)は、これを継承、委譲させてみたいと思います。
ではまた。


Recommendおすすめブログ