Cを用いたオブジェクト向けプログラミング

4448 ワード

概要
オブジェクト向けプログラミングはプログラミングのモデルです.このプログラミングパターンを用いて,データと操作をバインドしてカプセル化し,これらの操作手順を知る必要のないシステムの他の部分に情報の隠蔽を行った.オブジェクト向けの他の概念には、「マルチステート」と「継承」が含まれます.この2つの概念はOOプログラマーによって大量に使用され、よく区別されていない.この短文では,OOPとは何かを検討するのではなく,これらの概念がどのようにc言語で実現され,どのように正しく使用されるかを研究する.
OOPが偉大な思想であることを証明する良い例は、AVLツリーのようなデータ構造を格納することです.これらは複雑なデータ構造であり、データを格納したいたびに書き直したくありません.機能は非常に限られていますが.AVLツリーを実現するには、データ構造が必要です.もちろん、まず木です.各ノードには、親ノードを指すポインタがあります.比較子もいくつかあるかもしれません.各ノード(リーフノードかもしれない)には、ユーザデータへのポインタもあるかもしれません.また,左回り,右回り,およびこの2つの操作を組み合わせた方法もある.これらはすべてツリーを使用するのに欠けているコードではありません.1本の木を使うとき、あなたが関心を持っているのはいくつかのものを木の中に置いて、ある时にそれを取り出すことです.
メソッド呼び出し
OOPは言語特性ではなくプログラミングモデルであることに注意してください.C++はOOコードを書くのに役立つ特殊な文法がありますが、OOコードを書くには必ずこれらの特性を使うというわけではありません.OOPの最も重要な特性は、メソッドを呼び出し、これらのメソッドが動作するデータ上で正しい操作を行うことができることです.これは通常、いわゆるselfポインタによって実現される.c言語にはこのような特性がないので,方法はデータに自動的にアクセスする能力がない.次のようなコードは書けません
   1:  my_object->my_method(args);

逆に、次のように書く必要があります.
   1:  my_method(my_object, args);

もちろん、第1の文法の意味は明らかですが、第2の例は同じことをしています.selfポインタがないだけです.
不透明なデータ型
structをオブジェクトとして使用すると、提供した方法ではなくデータを直接操作する人がいます.このような状況を阻止する最善の方法は、対象がどのように組織されているかを教えないことだ.幸いなことに、C言語は不透明なタイプの概念を提供して、この仕事をよく完成することができます.構造を宣言しますが、定義しません.その後、コードはポインタでこれらのデータ型を使用できますが、このような構造を参照またはインスタンス化することはできません.avlツリーの例に戻ると、データ型は次のように定義できます.
   1:  struct my_avl_tree_s;
   2:  typedef struct my_avl_tree_s my_avl_tree_t;
 

メソッドの宣言と定義
AVLツリーを使用するには、構造を指すポインタを取得し、ツリーを操作するすべての方法に渡す必要があります.自分でこのような構造を割り当てたりインスタンス化したりすることはできないので、これらもオブジェクトが自分で完成しなければなりません.OOPでは、これをコンストラクション関数と呼びます.
   1:  my_avl_tree_t *my_avl_create(void);

オブジェクトの内部構造がよく分からないので、クリーンアップ作業をします.したがって、構造関数である関数を使用する必要があります.
   1:  void my_avl_destroy(my_avl_tree_t *obj);

ツリーを操作する方法:
   1:  void my_avl_insert(my_avl_tree_t *obj, const char *key, void *value);
   2:  void *my_avl_search(my_avl_tree_t *obj, const char *key);
   3:  void *my_avl_remove(my_avl_tree_t *obj, const char *key);

共通の関数を実現するには、モジュール内の関数がmy_を知る必要があります.avl_tree_t構造.すべての作業は、ヘッダファイルではなくモジュールファイルで構造を定義することです.
   1:  #include "my_avl_tree.h"
   2:   
   3:  struct my_avl_tree_s
   4:  {
   5:        my_avl_node_t *rootl;
   6:        uint32_t depth;
   1:  my_avl_tree *my_avl_create(void)
   2:  {
   3:      my_avl_tree_t *obj;
   4:     
   5:      obj = (my_avl_tree_t *)malloc(sizeof(my_avl_tree_t));
   6:      if(obj == NULL)
   7:          return NULL;
   8:      memset(obj, '\0', sizeof(my_avl_tree_t));
   9:      return  obj;
  10:  }

コンストラクション関数は、構造がどれだけ大きいかを知っていて、十分なメモリを簡単に割り当てることができます.